<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Programação - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Programação - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 09 May 2026 13:42:16 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/tag/programacao/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ A grande competição entre os termos usados em programação ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Preethi Kasireddy Imperativo x Declarativo, Puro x Impuro, Estático x Dinâmico. Terminologias como essas são salpicadas por várias publicações em blogs de programação, palestras em conferências, artigos e livros didáticos. Porém, você não deve se deixar intimidar por esse vocabulário. Vamos examinar e desvendar alguns desses conceitos para ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/a-grande-competicao-entre-os-termos-usados-em-programacao/</link>
                <guid isPermaLink="false">668de2da23266d03fc8b8675</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kris Lagerström ]]>
                </dc:creator>
                <pubDate>Sun, 28 Jul 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/1_d55K-aHn7CPPe-M83e_n5g.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/programming-mental-models-47ccc65eb334/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The Great Programming Jargon Bake-off</a>
      </p><p>Escrito por: Preethi Kasireddy</p><p>Imperativo x Declarativo, Puro x Impuro, Estático x Dinâmico.</p><p>Terminologias como essas são salpicadas por várias publicações em blogs de programação, palestras em conferências, artigos e livros didáticos.</p><p>Porém, você não deve se deixar intimidar por esse vocabulário. Vamos examinar e desvendar alguns desses conceitos para que você possa entender sobre o que todos esses desenvolvedores ao seu redor estão falando.</p><h3 id="tipagem-est-tica-x-din-mica">Tipagem estática x dinâmica</h3><p>Isso se trata de quando a informação de <em>tipo </em>é adquirida — seja no momento da compilação ou em tempo de execução.</p><p>Você pode usar essa informação de tipo para detectar erros de tipo. Um erro de tipo ocorre quando um valor não é do tipo esperado.</p><h4 id="verifica-o-de-tipo-est-tica">Verificação de tipo estática</h4><p>É o processo de verificar a segurança de tipo de um programa com base na análise do código-fonte do programa. Em outras palavras, a verificação de tipo ocorre no momento da compilação, permitindo que erros de tipo sejam detectados mais cedo.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/GD1KhgaCFzdaiATtb-MnKj3L-ZXUiIoydrc8.png" class="kg-image" alt="GD1KhgaCFzdaiATtb-MnKj3L-ZXUiIoydrc8" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/GD1KhgaCFzdaiATtb-MnKj3L-ZXUiIoydrc8.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/GD1KhgaCFzdaiATtb-MnKj3L-ZXUiIoydrc8.png 800w" sizes="(min-width: 720px) 720px" width="800" height="522" loading="lazy"><figcaption>À direita: os tipos de x e y são verificados no momento da compilação para garantir que as duas variáveis são do tipo <em>int</em>/Abaixo: quando você instancia a classe <em>Point</em>, os tipos de x e de y são verificados no momento da compilação para garantir que são do tipo <em>int</em></figcaption></figure><h4 id="verifica-o-de-tipo-din-mica">Verificação de tipo dinâmica</h4><p>O processo de verificar a segurança de tipo de um programa em tempo de execução. Com a verificação de tipo dinâmica, os erros de tipo ocorrem em tempo de execução.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/r0NYTBqJGSc8XLHqK8Et-rMW0tkOd3VI7I5u.png" class="kg-image" alt="r0NYTBqJGSc8XLHqK8Et-rMW0tkOd3VI7I5u" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/r0NYTBqJGSc8XLHqK8Et-rMW0tkOd3VI7I5u.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/r0NYTBqJGSc8XLHqK8Et-rMW0tkOd3VI7I5u.png 800w" sizes="(min-width: 720px) 720px" width="800" height="600" loading="lazy"><figcaption>À direita: os tipos de x e y são determinados no momento da execução/Abaixo: quando você instancia a classe <em>Point</em>, os tipos de x e de y não são verificados. Se você passar um valor de <em>string</em> para y, o programa o aceitará (e pode lançar um erro de tempo de execução se y for usado indevidamente)</figcaption></figure><h3 id="tipagem-forte-x-fraca">Tipagem forte x fraca</h3><p>É importante observar que forte x fraca não tem um significado técnico sobre o qual todos universalmente concordam. Por exemplo, mesmo que Java seja tipado estaticamente, toda vez que você usa reflexão ou <em>cast</em>, você está adiando a verificação de tipo para a execução.</p><p>Da mesma maneira, a maioria das linguagens fortemente tipadas ainda converterá automaticamente entre inteiros e ponto flutuante. Portanto, você deve evitar usar esses termos porque chamar um sistema de tipagem "forte" ou "fraca", por si só, não diz muito.</p><h4 id="tipagem-forte">Tipagem forte</h4><p>Em uma linguagem fortemente tipada, o tipo de uma construção não muda — um <code>int</code> é sempre um <code>int</code> e tentar usá-lo como uma <code>string</code> resultará em um erro.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/qQuFtQHI0nVeCYYPFiwmtPXD0I0VtUfQS3VH.png" class="kg-image" alt="qQuFtQHI0nVeCYYPFiwmtPXD0I0VtUfQS3VH" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/qQuFtQHI0nVeCYYPFiwmtPXD0I0VtUfQS3VH.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/qQuFtQHI0nVeCYYPFiwmtPXD0I0VtUfQS3VH.png 800w" sizes="(min-width: 720px) 720px" width="800" height="460" loading="lazy"></figure><h4 id="tipagem-fraca">Tipagem fraca</h4><p>Tipagem fraco significa que o tipo de uma construção pode mudar dependendo do contexto. Por exemplo, em uma linguagem de tipagem fraca, a string "123" pode ser tratada como o número 123 se você adicionar outro número a ela.</p><p>Isso geralmente significa que o sistema de tipos pode ser subvertido (invalidando quaisquer garantias) porque você pode converter um valor de um tipo para outro.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/iKBgNAycyEVpLytn2tivoY3U0wN-osYulEJr.png" class="kg-image" alt="iKBgNAycyEVpLytn2tivoY3U0wN-osYulEJr" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/iKBgNAycyEVpLytn2tivoY3U0wN-osYulEJr.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/iKBgNAycyEVpLytn2tivoY3U0wN-osYulEJr.png 800w" sizes="(min-width: 720px) 720px" width="800" height="577" loading="lazy"><figcaption>Adicionar a <em>string</em> "4" à soma de 4 + 4 = 8 resulta na <em>string</em> "8" + "4" = "84". Assim, adicionar a <em>string </em>a um número causou o <em>casting </em>(a conversão) do número 8 para uma <em>string</em>.</figcaption></figure><h3 id="dados-mut-veis-x-imut-veis">Dados mutáveis x imutáveis</h3><h4 id="dados-imut-veis">Dados imutáveis</h4><p>Quando um objeto não pode ser modificado após sua criação, você pode dizer que ele é "imutável", que é outro modo de dizer "inalterável". Isso significa que você alocará um novo valor para cada alteração.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/D3tF-qLMqDUXzFdHRRXy9jZm5ZrZ-DJVxi-p.png" class="kg-image" alt="D3tF-qLMqDUXzFdHRRXy9jZm5ZrZ-DJVxi-p" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/D3tF-qLMqDUXzFdHRRXy9jZm5ZrZ-DJVxi-p.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/D3tF-qLMqDUXzFdHRRXy9jZm5ZrZ-DJVxi-p.png 800w" sizes="(min-width: 720px) 720px" width="800" height="397" loading="lazy"></figure><h4 id="dados-mut-veis">Dados mutáveis</h4><p>Quando você pode modificar um objeto após sua criação, ele é "mutável". Quando você tem uma referência a um objeto mutável, por exemplo, o conteúdo do objeto pode mudar.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/lKF181TAlPPvUz0ln8VLksubyCYCbs8ocB73.png" class="kg-image" alt="lKF181TAlPPvUz0ln8VLksubyCYCbs8ocB73" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/lKF181TAlPPvUz0ln8VLksubyCYCbs8ocB73.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/lKF181TAlPPvUz0ln8VLksubyCYCbs8ocB73.png 800w" sizes="(min-width: 720px) 720px" width="800" height="456" loading="lazy"><figcaption>A variável <em>person</em> é mutável. Assim, podemos atualizar a propriedade <em>age</em> (idade)</figcaption></figure><h3 id="fun-es-puras-x-impuras">Funções puras x impuras</h3><h4 id="fun-es-puras">Funções puras</h4><p>Uma função pura tem duas qualidades:</p><ol><li>Ela depende apenas da entrada fornecida — e não de nenhum estado externo que possa mudar durante sua avaliação ou entre chamadas.</li><li>Ela não causa nenhum efeito colateral semanticamente observável, como modificar um objeto global ou um parâmetro passado por referência.</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/ir5sDGMoxckbC-wpR8JikApucz6DLkkPzGZx.png" class="kg-image" alt="ir5sDGMoxckbC-wpR8JikApucz6DLkkPzGZx" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/ir5sDGMoxckbC-wpR8JikApucz6DLkkPzGZx.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/ir5sDGMoxckbC-wpR8JikApucz6DLkkPzGZx.png 800w" sizes="(min-width: 720px) 720px" width="800" height="530" loading="lazy"><figcaption>A função depende somente das variáveis passadas explicitamente a ela, não alterando estados externos nem os argumentos passados a ela</figcaption></figure><h4 id="fun-es-impuras">Funções impuras</h4><p>Qualquer função que não atenda a esses dois requisitos para uma função pura é "impura".</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/J02vTF9q3BE9lIYoi2jV1QbJAqjRcMZJBw8L-1.png" class="kg-image" alt="J02vTF9q3BE9lIYoi2jV1QbJAqjRcMZJBw8L-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/J02vTF9q3BE9lIYoi2jV1QbJAqjRcMZJBw8L-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/J02vTF9q3BE9lIYoi2jV1QbJAqjRcMZJBw8L-1.png 800w" sizes="(min-width: 720px) 720px" width="800" height="534" loading="lazy"><figcaption>A função depende da variável global PI e altera o argumento de entrada <em>radii</em></figcaption></figure><h3 id="avalia-o-lenta-x-avalia-o-r-pida">Avaliação lenta x avaliação rápida</h3><h4 id="avalia-o-lenta">Avaliação lenta</h4><p>A avaliação lenta não avalia os argumentos da função a menos que seus valores sejam necessários para avaliar a própria chamada da função.</p><p>Em outras palavras, as expressões são avaliadas apenas quando ocorre a avaliação de outra expressão que depende da expressão atual.</p><p>A versão lenta das avaliações permite que os programas calculem estruturas de dados que são potencialmente <em>infinitas</em> sem travar.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/uxczq1DSf-SYP34fDk02eeBqbbEFaqwsUwP0.png" class="kg-image" alt="uxczq1DSf-SYP34fDk02eeBqbbEFaqwsUwP0" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/uxczq1DSf-SYP34fDk02eeBqbbEFaqwsUwP0.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/uxczq1DSf-SYP34fDk02eeBqbbEFaqwsUwP0.png 800w" sizes="(min-width: 720px) 720px" width="800" height="557" loading="lazy"><figcaption>Acima: vamos supor que temos uma função que filtra todos os números ímpares de 1 até o infinito e recebe os dez primeiros elementos/Abaixo: com a avaliação lenta, isso não é executado até que a operação que depende disso, <em>take</em>, é chamada.</figcaption></figure><h4 id="avalia-o-r-pida">Avaliação rápida</h4><p>A avaliação ávida — também conhecida como avaliação estrita — sempre avalia completamente os argumentos da função antes de invocar a função. Em outras palavras, uma expressão é avaliada assim que é vinculada a uma variável.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/SHUGZI2HS4n8mSPAWoUfWySxt8D4X0N5CXu-.png" class="kg-image" alt="SHUGZI2HS4n8mSPAWoUfWySxt8D4X0N5CXu-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/SHUGZI2HS4n8mSPAWoUfWySxt8D4X0N5CXu-.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/SHUGZI2HS4n8mSPAWoUfWySxt8D4X0N5CXu-.png 800w" sizes="(min-width: 720px) 720px" width="800" height="258" loading="lazy"><figcaption>Com a avaliação rápida, a função <em>range </em>tentará executar por inteiro antes de enviar seu resultado a <em>take</em>, o que leva a um <em>loop </em>infinito.</figcaption></figure><h3 id="declarativo-x-imperativo">Declarativo x imperativo</h3><h4 id="programa-o-declarativa">Programação declarativa</h4><p>Programas declarativos expressam um conjunto de operações sem revelar como são implementadas ou como os dados fluem através delas. Eles se concentram em "o que" o programa deve realizar (usando expressões para descrever a lógica) em vez de "como" o programa deve alcançar o resultado.</p><p>Um exemplo de programação declarativa é o SQL. As consultas SQL são compostas por instruções que descrevem como deve ser o resultado de uma consulta, enquanto abstraem o processo interno de como os dados são recuperados:</p><pre><code class="language-sql">SELECT EMP_ID, FIRST_NAME, LAST_NAMEFROM EMPLOYEES WHERE CITY = ‘SAN FRANCISCO’ ORDER BY EMP_ID;</code></pre><p>Aqui está um exemplo de código declarativo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/KJkzhjbfo5EYE2flsvDS9gT0JqAIcKcfklcA.png" class="kg-image" alt="KJkzhjbfo5EYE2flsvDS9gT0JqAIcKcfklcA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/KJkzhjbfo5EYE2flsvDS9gT0JqAIcKcfklcA.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/KJkzhjbfo5EYE2flsvDS9gT0JqAIcKcfklcA.png 761w" sizes="(min-width: 720px) 720px" width="761" height="655" loading="lazy"><figcaption>Usa <em>funções de ordem superior</em> para expressar <em>o que</em> o programa faz, não <em>como</em> o faz.</figcaption></figure><h4 id="programa-o-imperativa">Programação imperativa</h4><p>A programação imperativa concentra-se em descrever como um programa deve alcançar um resultado usando instruções que especificam o fluxo de controle ou alterações de estado. Ela usa uma sequência de instruções para calcular um resultado.</p><p>Aqui está um exemplo de código imperativo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/nWC5LzuByaWllxXsVXJS1pcYokOWlKxkZor2.png" class="kg-image" alt="nWC5LzuByaWllxXsVXJS1pcYokOWlKxkZor2" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/nWC5LzuByaWllxXsVXJS1pcYokOWlKxkZor2.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/nWC5LzuByaWllxXsVXJS1pcYokOWlKxkZor2.png 800w" sizes="(min-width: 720px) 720px" width="800" height="544" loading="lazy"><figcaption>Informa ao programa como executar a tareda usando <em>loops</em> e instruções <em>if-else</em></figcaption></figure><h3 id="com-estado-x-sem-estado">Com estado x sem estado</h3><p>Um estado (em inglês, <em>state</em>) é uma sequência de valores calculados progressivamente, que contém os resultados intermediários de um cálculo.</p><h4 id="com-estado">Com estado</h4><p>Programas com estado (do inglês., <em>stateful</em>) têm algum mecanismo para acompanhar e atualizar o estado. Eles têm alguma memória do passado e lembram transações anteriores que podem afetar a transação atual.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/2MCDlKSDdS9imKRxHECiksWO2jjxjeV1ndVB.png" class="kg-image" alt="2MCDlKSDdS9imKRxHECiksWO2jjxjeV1ndVB" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/2MCDlKSDdS9imKRxHECiksWO2jjxjeV1ndVB.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/2MCDlKSDdS9imKRxHECiksWO2jjxjeV1ndVB.png 782w" sizes="(min-width: 720px) 720px" width="782" height="646" loading="lazy"><figcaption>Essa função tem conhecimento do passado. Ela sabe o valor da variável <em>count</em>.</figcaption></figure><h4 id="sem-estado">Sem estado</h4><p>Programas sem estado (do inglês, <em>stateless</em>), por outro lado, não acompanham o estado. Não há memória do passado. Cada transação é realizada como se estivesse sendo feita pela primeira vez. Programas <em>stateless</em> darão a mesma resposta para o mesmo pedido, função ou chamada de método — todas as vezes.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/O4aqQxCiZF-tsYmo4yl34wrLs8wGOsWODvy3.png" class="kg-image" alt="O4aqQxCiZF-tsYmo4yl34wrLs8wGOsWODvy3" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/O4aqQxCiZF-tsYmo4yl34wrLs8wGOsWODvy3.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/O4aqQxCiZF-tsYmo4yl34wrLs8wGOsWODvy3.png 800w" sizes="(min-width: 720px) 720px" width="800" height="534" loading="lazy"><figcaption>Essa função não tem conhecimento do passado. A variável <em>count</em> é passada como um parâmetro e a função simplesmente retorna um resultado a partir daquilo que é passado para ela.</figcaption></figure><h3 id="funcional-x-orientada-a-objetos">Funcional x orientada a objetos</h3><h4 id="funcional">Funcional</h4><p>A programação funcional é um paradigma que enfatiza o uso de funções. O objetivo da programação funcional é usar funções para abstrair fluxos de controle e operações em dados, evitando efeitos colaterais.</p><p>Então, a programação funcional usa funções puras e evita dados mutáveis, o que, por sua vez, fornece <em>transparência referencial</em>.</p><p>Uma função tem transparência referencial quando você pode substituir livremente uma expressão por seu valor e não mudar o comportamento do programa. Dito de um modo um pouco diferente: para uma determinada entrada, ele sempre retorna os mesmos resultados.</p><p>Alguns exemplos de linguagens que enfatizam a programação funcional incluem Haskell, Lisp, Clojure e Elm. Você pode, contudo, usar conceitos de programação funcional na maioria das linguagens, incluindo em JavaScript.</p><h4 id="orientada-a-objetos">Orientada a objetos</h4><p>O paradigma de programação orientada a objetos enfatiza o uso de objetos. Isso resulta em programas que são feitos de objetos que interagem entre si. Esses objetos podem conter dados (na forma de campos ou atributos) e comportamento (na forma de métodos).</p><p>É um estilo de particionamento (ou encapsulamento) do estado de um programa através de objetos para tornar a análise do efeito das mudanças tratável [1].</p><p>Além disso, programas orientados a objetos usam herança e/ou composição como seus principais mecanismos para reutilização de código. Herança significa que uma nova classe pode ser definida em termos de classes existentes especificando apenas como a nova classe é diferente. Representa um relacionamento "é um" (por exemplo, uma classe <code>Pássaro</code> que estende uma classe <code>Animal</code>). A composição, por outro lado, é quando as classes contêm instâncias de outras classes que implementam a funcionalidade desejada. Representa um relacionamento "tem um" (por exemplo, uma classe <code>Pássaro</code> tem uma instância de uma classe <code>Asa</code> como membro).</p><p>O polimorfismo também é um mecanismo importante para a reutilização de código na programação orientada a objetos. É quando uma linguagem pode processar objetos de maneira diferente dependendo de seu tipo de dados ou classe.</p><p>Alguns exemplos de linguagens que enfatizam a programação orientada a objetos incluem Java, C++, Ruby. Novamente, você pode aplicar esses conceitos na maioria das linguagens, incluindo em JavaScript.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/N8MHF9tH7WY137DollJShA9icCiaduLFJS9O.png" class="kg-image" alt="N8MHF9tH7WY137DollJShA9icCiaduLFJS9O" width="578" height="655" loading="lazy"><figcaption>Comentários em ordem (de cima para baixo): Métodos de instâncias usam "this" para acessar os dados do objeto/Herança/Dados mutáveis</figcaption></figure><h3 id="determin-stico-x-n-o-determin-stico">Determinístico x não determinístico</h3><h4 id="determin-stico">Determinístico</h4><p>Programas determinísticos sempre retornam o mesmo resultado sempre que são chamados com um conjunto específico de valores de entrada e o mesmo estado fornecido.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/QZcUv8Ergv0DU4N3SSrR6SFbajhNRXzagcTr.png" class="kg-image" alt="QZcUv8Ergv0DU4N3SSrR6SFbajhNRXzagcTr" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/QZcUv8Ergv0DU4N3SSrR6SFbajhNRXzagcTr.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/QZcUv8Ergv0DU4N3SSrR6SFbajhNRXzagcTr.png 800w" sizes="(min-width: 720px) 720px" width="800" height="416" loading="lazy"><figcaption>Não importa o número de vezes que invocarmos a função <em>add</em>, os resultados sempre serão os mesmos.</figcaption></figure><h4 id="n-o-determin-stico">Não determinístico</h4><p>Programas não determinísticos podem retornar resultados diferentes cada vez que são chamados, mesmo com o mesmo conjunto específico de valores de entrada e estado inicial.</p><p>O não determinismo é uma propriedade de qualquer sistema concorrente — ou seja, qualquer sistema em que várias tarefas podem acontecer ao mesmo tempo, executando em diferentes <em>threads</em>. Um algoritmo concorrente que está alterando o estado pode se comportar de maneira diferente a cada vez, dependendo de qual <em>thread </em>o agendador decidir executar.</p><p>Por exemplo:</p><pre><code>declare Xthread X=1 endthread X=2 end</code></pre><p>A ordem de execução das duas <em>threads </em>não é fixa. Não sabemos se X será vinculado a 1 ou 2. O sistema escolherá durante a execução do programa, sendo livre para escolher qual <em>thread </em>executar primeiro.</p><p>Outro exemplo de não determinismo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/V0yGj2uPPh5HUKf25kTgQiGZwLG8eAsRjkXM.png" class="kg-image" alt="V0yGj2uPPh5HUKf25kTgQiGZwLG8eAsRjkXM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/V0yGj2uPPh5HUKf25kTgQiGZwLG8eAsRjkXM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/V0yGj2uPPh5HUKf25kTgQiGZwLG8eAsRjkXM.png 800w" sizes="(min-width: 720px) 720px" width="800" height="569" loading="lazy"><figcaption>Temos dois resultados possíveis para os valores resultantes de <em>a</em> e de <em>b</em>, dependendo de qual chamada de API é retornada primeiro./Se a primeira chamada de API retorna antes da segunda, foo será invocada antes de bar, <em>a</em> será 15 e <em>b</em> será 3. Caso contrário, <em>a</em> será 13 e <em>b</em> será 2.</figcaption></figure><h3 id="conclus-o">Conclusão</h3><p>Como sempre, seu <em>feedback </em>e sua contribuição são realmente importantes para mim. Você também pode conferir a <a href="https://prezi.com/fftgbgltl-6u/programming-models/?utm_campaign=share&amp;utm_medium=copy">apresentação do Prezi</a> que criei para este artigo.</p><p>[1] Um agradecimento especial a <a href="https://twitter.com/kentbeck">Kent Beck</a> por sua contribuição para este artigo.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Já programamos há milhares de anos ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Tautvilas Mečinskas Programas de computador estão por toda parte. Interagimos com eles todos os dias. Parece que os softwares estão se tornando cada vez mais importantes para a nossa sociedade. Por que, no entanto, achamos os programas tão necessários? Por que e quando começamos a programar? Qual é ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/ja-programamos-ha-milhares-de-anos/</link>
                <guid isPermaLink="false">668dda5023266d03fc8b866e</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kris Lagerström ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jul 2024 00:59:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/1_baG6RijcVa8LysywkCpN8g.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/what-is-programming-22a72ef4fd02/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">We have been programming for thousands of years</a>
      </p><p>Escrito por: Tautvilas Mečinskas</p><p>Programas de computador estão por toda parte. Interagimos com eles todos os dias. Parece que os softwares estão se tornando cada vez mais importantes para a nossa sociedade. Por que, no entanto, achamos os programas tão necessários? Por que e quando começamos a programar? Qual é a essência da programação? Essas perguntas podem parecer triviais, mas sinto que hoje ainda não temos uma boa definição do que é programação. Talvez este artigo possa ajudar a mudar isso.</p><p>É bastante difícil definir programação porque ela é muito diversa. Pode-se programar jogos, aplicações para dispositivos móveis, sites, compiladores, simulações e muito mais. Nesse caso, pode ser útil começar eliminando algumas ideias preconcebidas e esclarecer o que a programação não é.</p><p><strong>Programação não é ciência.</strong> A ciência é a arte de examinar o mundo e descobrir padrões repetitivos nele. O método científico consiste em fazer uma hipótese e, em seguida, realizar experimentos para provar ou rejeitá-la. Não usamos esse método na programação – portanto, não é ciência. A programação não se trata de descoberta, mas de criatividade.</p><p><strong>Programação não é matemática.</strong> Sim, há um aspecto matemático na programação. Algumas partes dos programas podem ser expressas como funções matemáticas. Escrever um gerador de números de Fibonacci é divertido, mas completamente inútil sem uma aplicação no mundo real. A matemática na programação é um meio para um fim, não uma parte central do processo.</p><p><strong>Programação não se trata de computadores eletrônicos.</strong> Computadores são muito úteis, mas não são necessários. Os programas podem ser entendidos e interpretados por seres humanos também. Portanto, os computadores são apenas ferramentas que usamos na programação.</p><p>Então, do que se trata a programação? O que se encontra dentro de todo programa, seja ele ou pequeno?</p><p>Abstrações.</p><p>O que é abstração? É uma imagem reduzida do mundo. Ao abstrair, estamos convertendo a realidade em símbolos que podem ser transmitidos como informação. A palavra <em>abstração</em> origina-se de duas palavras latinas, que são <em>abs</em>, que significa <em>longe de</em> e <em>trahere</em>, que significa <em>desenhar</em>. A tradução latina sugere que abstrair implica separar algo do todo.</p><p>O processo de abstração é único da programação? De fato, não. É algo que os humanos fazem há bastante tempo. Nossas ferramentas de abstração mais básicas são o mapa e o relógio.</p><p>Arqueólogos descobriram mapas de pedra que os humanos fizeram há mais de 14 mil anos. Isso mostra que a cartografia é fundamental para os humanos. É um processo de transformar território em símbolos abstratos. Um mapa é um modo de abstrair o espaço. É uma ferramenta que nos ajuda a fazer sentido do território ao nosso redor para que a navegação seja mais fácil.</p><p>Um relógio, por outro lado, é um modo de abstrair o tempo. Achamos a natureza contínua do tempo confusa. Por isso, a abstraímos. Os humanos dividem o tempo em intervalos discretos: anos, meses, dias, horas, minutos, segundos. Enquanto um mapa nos ajuda a navegar no espaço, um relógio nos ajuda a navegar no tempo. O predecessor do relógio - o calendário - surgiu há mais de 10 mil anos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/K2-yzsletJjBjTnKwA7kvn4sz4Ynu1UOC3ou.jpg" class="kg-image" alt="K2-yzsletJjBjTnKwA7kvn4sz4Ynu1UOC3ou" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/K2-yzsletJjBjTnKwA7kvn4sz4Ynu1UOC3ou.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/K2-yzsletJjBjTnKwA7kvn4sz4Ynu1UOC3ou.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="587" loading="lazy"><figcaption>O gigante calendário solar de <a href="https://en.wikipedia.org/wiki/Chankillo">Chankillo</a> foi construído há 2.300 anos.</figcaption></figure><p>Já aos computadores são ferramentas que também lidam com abstrações. Há 3 partes fundamentais em todo computador:</p><ol><li>Relógio interno – a maneira de o computador abstrair o tempo</li><li>Memória – a maneira de o computador abstrair o espaço</li><li>Unidade de processamento – a maneira de o computador executar operações lógicas</li></ol><p>Esses recursos dão aos computadores uma maneira de entender abstrações espaciais e suas interações no tempo abstrato. Isso significa que os programas são abstrações do espaço e do tempo. A programação é a arte de criar abstrações do espaço e do tempo. Essas abstrações nos ajudam a navegar na realidade, sendo, por isso, tão importantes para nós.</p><p>Existe um método de abstração que é muito semelhante à programação, mas que é ainda mais antigo que mapas, relógios e calendários: a linguagem.</p><p>Se você olhar de perto para nossa linguagem natural, verá que ela possui todas as características necessárias para abstrair o espaço e o tempo.</p><p>Vamos analisar um exemplo de frase:</p><blockquote>Vá para o jardim e colha algumas flores esta noite.</blockquote><p><strong>O jardim</strong> e as <strong>flores</strong> referem-se a espaço abstrato. <strong>Esta noite</strong> é um modo de abstrair o tempo. <strong>E</strong> adiciona lógica à frase. <strong>Vá para</strong> e <strong>colha</strong> são sub-rotinas.</p><p>Podemos facilmente transformar a frase acima em JavaScript:</p><pre><code class="language-js">quandoNoite.then(()=&gt;voce.irPara(jardim)).then(()=&gt;voce.pegar(flor))
</code></pre><p>Essa frase pode ser entendida por um computador que tenha definições de <strong>noite</strong>, <strong>você</strong>, <strong>flores</strong> e as sub-rotinas necessárias definidas.</p><p>O problema da linguagem natural é que ela tem aplicações muito amplas. A linguagem pode ser usada não apenas para comunicar informações, mas também para expressar sentimentos e emoções. Os melhores exemplos de programas de linguagem natural pura são leis, regras de jogos de tabuleiro e manuais de instruções.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/xQoLcFFm2PL69Hv3LpF1saAtoAn86lGejQ99.jpg" class="kg-image" alt="xQoLcFFm2PL69Hv3LpF1saAtoAn86lGejQ99" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/xQoLcFFm2PL69Hv3LpF1saAtoAn86lGejQ99.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/xQoLcFFm2PL69Hv3LpF1saAtoAn86lGejQ99.jpg 640w" width="640" height="423" loading="lazy"><figcaption>O <a href="https://pt.wikipedia.org/wiki/C%C3%B3digo_de_Hamurabi">Código de Hamurabi</a> é um dos mais antigos programas de linguagem natural (foto de <a href="https://www.flickr.com/photos/prof_richard/">Richard</a> / <a href="https://creativecommons.org/licenses/by-nc-sa/2.0/">CC BY-NC-SA</a>)</figcaption></figure><p>As linguagens de programação, por outro lado, são rigorosas e só podem criar abstrações. Os computadores são projetados para interpretar essas abstrações de uma maneira muito específica e determinística.</p><p>Para escrever programas de computador, você precisa aprender a programar a linguagem natural em símbolos que o computador possa entender. Isso geralmente requer conhecimento intrincado da arquitetura do computador e da sintaxe da linguagem de computador escolhida. Portanto, se você quiser que um computador entenda suas abstrações de realidade, você precisa aprender a programar.</p><p>Os computadores são ferramentas que podem executar regras definidas em programas com velocidade e precisão sobre-humanas. Eles nos capacitam a construir abstrações complexas e multicamadas e a transformar nossos programas em mapas da realidade verdadeiramente dinâmicos e interativos.</p><p>De muitas maneiras, programar é algo que todos nós já sabemos fazer. O processo de abstração da realidade é fundamental para os seres humanos. A programação de computadores é apenas a maneira mais eficaz de se fazer isso.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Lições do meu primeiro ano programando ao vivo na Twitch ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Suz Hinton Resolvi tentar fazer streaming (transmissão ao vivo) pela primeira vez em julho passado. Em vez de jogos, como a maioria dos streamers na Twitch faz, eu queria transmitir o trabalho com código aberto que faço no meu tempo livre. Eu trabalho um pouco em bibliotecas de ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/licoes-do-meu-primeiro-ano-programando-ao-vivo-na-twitch/</link>
                <guid isPermaLink="false">665b5f3fe669e903cefde54e</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Sun, 16 Jun 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_EyRimlrHNEKeFmS4.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/lessons-from-my-first-year-of-live-coding-on-twitch-41a32e2f41c1/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Lessons from my first year of live coding on Twitch</a>
      </p><p>Escrito por: Suz Hinton</p><p>Resolvi tentar fazer <em>streaming</em> (transmissão ao vivo) pela primeira vez em julho passado. Em vez de jogos, como a maioria dos <em>streamers </em>na Twitch faz, eu queria transmitir o trabalho com código aberto que faço no meu tempo livre. Eu trabalho um pouco em bibliotecas de hardware do NodeJS (a maioria delas feita por mim). Como que eu já estava em um nicho na Twitch, por que não estar em um nicho ainda menor, como hardware com JavaScript? 😉 Então, fiz meu próprio canal e tenho transmitido regularmente desde então.</p><p>Claro que não fui a primeira a fazer isso. <a href="https://www.twitch.tv/handmade_hero" rel="noopener">Handmade Hero</a> foi um dos primeiros programadores que eu assisti programando <em>on-line</em>, seguido logo depois por Vlambeer, que <a href="http://nuclearthrone.com/twitch/" rel="noopener">desenvolveu Nuclear Throne ao vivo na Twitch</a>. Em especial, eu era fascinada por Vlambeer.</p><p>O que me fez cruzar a barreira de <em>desejar</em> fazer e passar a <em>fazer de fato</em> tem a ver com <a href="https://twitter.com/nolanlawson" rel="noopener">Nolan Lawson</a>, um amigo meu. Assisti a um <a href="https://www.youtube.com/watch?v=9FBvpKllTQQ" rel="noopener">streaming dele mostrando um final de semana de seu trabalho com código aberto</a> e achei aquilo incrível. Ele explicava tudo o que estava fazendo enquanto programava. Tudo. Respondia a problemas no GitHub, fazia a triagem dos <em>bugs</em>, depurava o código das <em>branches</em>, absolutamente tudo o que você pode imaginar. Eu achei fascinante, pois Nolan mantém bibliotecas de código aberto que recebem muita atividade e são muito usadas. Sua vida trabalhando no código aberto é muito diferente da minha.</p><p>Você consegue até ver um comentário que eu deixei no vídeo dele:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 75%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="150" src="https://www.youtube.com/embed/9FBvpKllTQQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Nolan Lawson does open-source, episode 1" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p>Eu tentei por conta própria uma semana depois ou algo assim depois de configurar meu canal na Twitch e de me encontrar no <a href="https://obsproject.com/">OBS Studio</a>. Acho que trabalhei com o <a href="https://github.com/noopkat/avrgirl-arduino" rel="noopener">Avrgirl-Arduino</a>, no qual eu ainda trabalho com frequência quando faço meus <em>streamings</em>. Foi um primeiro <em>streaming</em> bem complicado. Eu estava muito nervosa. Fiquei até altas horas ensaiando tudo o que eu faria na noite anterior.</p><p>O pequeno número de espectadores que recebi naquele sábado foi realmente encorajador. Então, eu continuei fazendo. Hoje em dia, tenho mais de mil seguidores e um lindo subconjunto deles são visitantes regulares que eu chamo de "a família <em>noopkat</em>".</p><p>Nos divertimos muito – e eu gosto de chamar as partes de programação ao vivo de "programação com pares on-line em massa para multijogadores". Fico verdadeiramente tocada pela bondade e sagacidade de todos que se juntam a mim a cada fim de semana. Um dos momentos mais engraçados que tive foi quando um membro da família apontou que minha placa Arduino não estava funcionando com meu software porque o microchip não estava na placa.</p><p>Diversas vezes, eu costumava encerrar um <em>streaming </em>e, pouco depois, descobria que na minha caixa de entrada do e-mail que alguém havia feito um <em>pull request</em> para algum trabalho que eu havia mencionado e não tinha o tempo para iniciá-lo. Eu posso dizer honestamente que meu trabalho em código aberto mudou para melhor, graças à generosidade e encorajamento da minha comunidade na Twitch.</p><p>Tenho muito mais a dizer sobre os benefícios que o <em>streaming</em> na Twitch me trouxe, mas isso é para outro artigo, provavelmente. Em vez disso, quero compartilhar as lições que aprendi com qualquer outra pessoa que gostaria de tentar programar ao vivo dessa maneira para si mesma. Recentemente, fui questionada por alguns desenvolvedores sobre como eles podem começar. Então, estou publicando o mesmo conselho que dei a eles!</p><p>Para começar, deixo aqui um link para um guia chamado "<a href="https://www.reddit.com/r/Twitch/comments/4eyva6/a_guide_to_streaming_and_finding_success_on_twitch/" rel="noopener">Streaming and Finding Success on Twitch</a>" (algo como "fazendo <em>streaming</em> e tendo sucesso na Twitch", texto em inglês), que me ajudou demais. O foco é na Twitch e nos <em>streamings</em> de jogos especificamente, mas ainda há seções relevantes e dicas preciosas ali. Recomendo a leitura antes de considerar outros detalhes sobre como começar seu canal (como o equipamento ou a escolha do <em>software</em>).</p><p>Já os meus conselhos, você pode ver a seguir. São dicas que eu compartilho agora e que vêm dos meus próprios erros e da sabedoria infinita de <em>streamers</em> conhecidos meus (que sabem muito bem que estou falando deles).</p><h3 id="software"><strong>Software</strong></h3><p>Há muito <em>software </em>de <em>streaming</em> por aí que você pode usar. Eu uso o <a href="https://obsproject.com/" rel="noopener">Open Broadcaster Software (OBS)</a>. Ele está disponível para a maioria das plataformas. Eu descobri que, para mim, ele era bastante intuitivo, que eu conseguiria configurá-lo e colocá-lo a funcionar rapidamente. Sei, porém, que outras pessoas podem passar bastante tempo até aprender como ele funciona. Vai depender de uma pessoa para outra! Aqui está uma tela que mostra como minha configuração de cena do desktop via OBS é ainda hoje:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_s4wyeYuaiThV52q5.png" class="kg-image" alt="0_s4wyeYuaiThV52q5" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/06/0_s4wyeYuaiThV52q5.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_s4wyeYuaiThV52q5.png 800w" width="800" height="666" loading="lazy"></figure><p>Essencialmente, você alterna entre 'cenas' enquanto faz seu <em>streaming</em>. Uma cena é uma coleção de 'fontes', em camadas e compostas entre elas. uma fonte pode consistir em coisas como uma câmera, microfone, seu desktop, uma página da web, texto ao vivo, imagens, entre várias outras. O OBS é muito poderoso.</p><p>Essa cena do desktop acima é onde eu faço toda a programação ao vivo. Eu praticamente "vivo" aqui durante quase todo o <em>streaming</em>. Eu uso iTerm e o vim. Tenho também uma janela do navegador à mão para onde eu vou para procurar documentação e para fazer uma triagem em coisas no GitHub etc.</p><p>O retângulo inferior em preto é a minha webcam, para que os usuários possam me ver trabalhando e ter uma conexão mais pessoal.<br><br>Eu tenho alguns 'rótulos' que eu uso para minhas cenas, muitos dos quais tem a ver com as estatísticas e informações no banner superior. O banner simplesmente adiciona um pouco de personalidade. É uma fonte persistente de informações legal durante o <em>streaming</em>. É uma imagem que fiz no <a href="https://www.gimp.org/" rel="noopener">GIMP</a> e você pode importá-la como fonte em sua cena. Alguns dos rótulos são estatísticas ao vivo que vêm de arquivos de texto (como, por exemplo, quem é o seguidor mais recente). Outro rótulo é um <a href="https://github.com/noopkat/study-temp" rel="noopener">personalizado que eu fiz</a> e que mostra a temperatura ao vivo e a umidade do ambiente de onde eu faço o <em>streaming</em>.</p><p>Eu também tenho 'alertas' configurados em minhas cenas, que mostram banners bonitos na parte superior do <em>streaming</em> sempre que alguém me segue ou doa algum dinheiro. Eu uso o serviço da web chamado <a href="https://streamlabs.com/" rel="noopener">Stream Labs</a> para fazer isso, importando-o como uma fonte de página da web do navegador na cena. Stream Labs também cria um arquivo de texto com meus seguidores mais recentes para mostrar no meu banner.</p><p>Além disso, eu tenho uma tela de aguardo, que uso quando estou prestes a entrar ao vivo:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_cbkVjKpyWaWZLSfS.png" class="kg-image" alt="0_cbkVjKpyWaWZLSfS" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/06/0_cbkVjKpyWaWZLSfS.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_cbkVjKpyWaWZLSfS.png 800w" sizes="(min-width: 720px) 720px" width="800" height="669" loading="lazy"></figure><p>Também fiz uma cena para quando eu estou inserindo <em>tokens </em>secretos ou chaves de API. Eu apareço na câmera, mas meu desktop fica oculto com uma página da web divertida, de modo que eu posso trabalhar com privacidade:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_gbhowQ37jr3ouKhL.png" class="kg-image" alt="0_gbhowQ37jr3ouKhL" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/06/0_gbhowQ37jr3ouKhL.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_gbhowQ37jr3ouKhL.png 800w" sizes="(min-width: 720px) 720px" width="800" height="669" loading="lazy"></figure><p>Como você pode ver, eu não levo nada muito a sério quando estou fazendo meus <em>streamings</em>, mas eu gosto de ter uma configuração legal para que meus espectadores possam aproveitar ao máximo o <em>streaming</em>.</p><p>Agora, vamos a um segredo de verdade: eu uso o OBS para remover a parte inferior e a parte direita da minha tela, ao mesmo tempo em que mantenho o tamanho de vídeo que a Twitch espera. Isso me deixa com espaço para ver meus eventos (seguidores novos e outros) na parte inferior e eu posso olhar e responder na caixa de chat do meu canal à direita. A Twitch permite que você 'extraia' a caixa do chat para uma nova janela, o que é bastante útil.</p><p>Essa é a aparência do meu desktop completo <em>de fato</em>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_sENLkp3Plh7ZTjJt.png" class="kg-image" alt="0_sENLkp3Plh7ZTjJt" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/06/0_sENLkp3Plh7ZTjJt.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_sENLkp3Plh7ZTjJt.png 800w" sizes="(min-width: 720px) 720px" width="800" height="450" loading="lazy"></figure><p>Comecei a fazer isso há alguns meses e não parei mais. Eu nem tenho certeza se meus espectadores percebem que é assim que minha configuração funciona. Eu acho que eles dão como certo que eu posso ver tudo, mesmo que eu não possa ver o que realmente está sendo transmitido ao vivo quando eu estou ocupada programando!</p><p>Você deve estar se perguntando por que eu só uso um monitor. É porque dois monitores era demais para gerenciar além de tudo o que eu já estava fazendo durante o <em>streaming</em>. Eu descobri isso rapidamente e tenho ficado com apenas uma tela desde então.</p><h3 id="hardware"><strong>Hardware</strong></h3><p>Usei coisas mais baratas para começar e, aos poucos, comprei coisas mais legais quando percebi que o <em>streaming </em>seria algo a que eu me apegaria. Use o que tiver ao começar, mesmo que seja o microfone e a câmara integrados do seu laptop.</p><p>Hoje em dia, eu uso uma webcam Logitech Pro C920 e um microfone Blue Yeti em um braço de microfone com um suporte anti-impacto (do tipo aranha <em>shock</em>). Vale totalmente a pena no final, se você tiver o dinheiro para gastar. Fez muita diferença na qualidade dos meus <em>streamings</em>.</p><p>Eu uso um monitor grande (27 polegadas), porque, como eu mencionei anteriormente usar dois monitores simplesmente não funcionou para mim. Eu estava perdendo coisas no bate-papo porque eu não estava olhando para a segunda tela do laptop o suficiente, e assim por diante. O nível de experiência das pessoas pode variar aqui, mas ter tudo em uma tela foi fundamental para eu prestar atenção em tudo o que está acontecendo.</p><p>Em termos de hardware, acho que é isso. Não tenho uma configuração muito complicada.</p><p>Se você estava interessado, minha mesa é bastante normal, exceto pelo microfone assustador que fica grudado do meu lado:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_EyRimlrHNEKeFmS4--1-.jpg" class="kg-image" alt="0_EyRimlrHNEKeFmS4--1-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/06/0_EyRimlrHNEKeFmS4--1-.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_EyRimlrHNEKeFmS4--1-.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="533" loading="lazy"></figure><h3 id="dicas"><strong>Dicas</strong></h3><p>Esta última seção tem algumas dicas gerais que eu escolhi, que tornaram meu <em>streaming</em> melhor e mais agradável no geral.</p><h4 id="pain-is"><strong>Painéis</strong></h4><p>Dedique um tempo a criar ótimos painéis. Os painéis são as pequenas caixas de conteúdo na parte inferior da página do canal de todos. Eu os vejo como as novas caixas de perfil do MySpace (verdade). As ideias do painel podem ser coisas como regras de bate-papo, informações sobre quando você transmite, qual computador e equipamento você usa ou sua raça de gato favorita – qualquer coisa que crie um toque pessoal. Examine outros canais (especialmente os populares) para ter ideias!</p><p>Um exemplo de um dos meus painéis:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/0_HlLs6xlnJtPwN4D6.png" class="kg-image" alt="0_HlLs6xlnJtPwN4D6" width="342" height="433" loading="lazy"></figure><h4 id="chat"><strong>Chat</strong></h4><p>O chat é muito importante. Você receberá as mesmas perguntas repetidamente à medida que as pessoas entrarem durante o seu streaming depois de perderem o início. É aí que 'macros' de chat podem realmente ajudar. "Em que você está trabalhando?" é a pergunta mais comum feita enquanto estou programando. Eu tenho 'comandos' de atalho no chat para isso, que fiz com o <a href="https://beta.nightbot.tv/" rel="noopener">Nightbot</a>. Eles colocam uma explicação de algo que eu inseri anteriormente. Eu só preciso digitar um pequeno comando de uma palavra como <em><em>!whatamidoing</em> </em>(o que estou fazendo no momento).</p><p>Quando as pessoas fizerem perguntas ou deixarem comentários legais, fale com elas! Agradeça, diga seu identificador da Twitch, e eles realmente apreciarão a atenção e o reconhecimento. Isso é MUITO difícil de cuidar quando você começa a transmitir, mas a multitarefa virá mais fácil à medida que você fizer mais e mais. Tente passar alguns segundos a cada dois minutos olhando o chat para encontrar novas mensagens.</p><p>Ao programar, <em><em>expl</em>ique o que está fazendo</em>. Fale bastante. Faça piadas. Mesmo quando estou bloqueada com algo, eu digo coisas como, "Ah, droga, me esqueci de como usar esse método. Vou olhar no Google hahaha" e as pessoas são sempre legais. Algumas vezes, eles até leem com você e a ajudam. É divertido e uma maneira de engajar, além de manter as pessoas assistindo.</p><p>Eu perco o interesse rapidamente ao assistir streamings de programação onde a pessoa se senta em silêncio digitando código, ignorando o chat e seus novos alertas de seguidores.</p><p>Com quase toda certeza, 99% das pessoas que encontrarem seu canal serão amigáveis e curiosas. A gente até recebe um <em>troll</em> de vez em quando, mas as ferramentas de moderação oferecidas pela Twitch e pelo Nightbot ajudam muito a desencorajar esse tipo de comportamento.</p><h4 id="tempo-de-prepara-o"><strong>Tempo de preparação</strong></h4><p>Automatize sua configuração o máximo possível. Meu terminal é um iTerm, e ele permite que você salve arranjos de janelas e tamanhos de fonte para que você possa restaurá-los mais tarde. Eu tenho um arranjo de janela para <em>streaming</em> e outro para quando não estou no streaming. Isso me poupa muito tempo. Eu uso um comando e tudo está no tamanho perfeito e na posição certa, pronto para funcionar.</p><p>Existem outras aplicações por aí que automatizam todos os posicionamentos da janela da aplicação – procure para ver se alguma deles também ajudaria você.</p><p>Deixe o tamanho da fonte bem grande no seu terminal e no seu editor de código para que todos possam ver.</p><h4 id="regularidade"><strong>Regularidade</strong></h4><p>Mantenha-se regular em sua agenda. Eu só transmito uma vez por semana, mas sempre na mesma hora. Avise as pessoas se você não conseguir transmitir durante o tempo em que você normalmente faz isso. Isso me rendeu um público regular. Algumas pessoas adoram a rotina e é exatamente como conversar com um amigo. Você está em um círculo social com sua comunidade. Então, trate-a dessa maneira.</p><p>Quero transmitir mais vezes, mas sei que não posso me comprometer com mais de uma vez por semana por causa das minhas viagens. Estou tentando criar uma maneira de transmitir em alta qualidade quando estiver na estrada, ou, talvez, de apenas ter bate-papos casuais e de deixar a programação para o meu <em>streaming</em> normal de domingo. Ainda estou tentando descobrir como fazer isso!</p><h4 id="estranheza"><strong>Estranheza</strong></h4><p>Vai parecer estranho quando você começar. Você vai se sentir nervoso com as pessoas vendo você programar. Isso é normal! Senti isso muito forte no início, apesar de ter experiência em falar em público. Senti que não havia onde me esconder – e isso me assustou. Eu pensava: "todo mundo vai achar que meu código é ruim e que eu sou uma péssima desenvolvedora". Esse é um padrão de pensamento que me atormentou durante toda a minha carreira, no entanto. Não é uma novidade. Eu sabia que, ao vivo, eu não conseguiria refatorar silenciosamente o código antes de enviar para o GitHub, o que, geralmente, é muito mais seguro para minha reputação como desenvolvedora.</p><p>Aprendi muito sobre meu estilo de programação fazendo isso ao vivo na Twitch. Aprendi que sou definitivamente do tipo "primeiro, faça funcionar; depois, torne legível; por fim, torne mais rápido". Eu não ensaio mais na noite anterior (desisti disso depois de 3 ou 4 transmissões iniciais). Então, escrevo um código bem tosco na Twitch e tenho que me sentir bem com isso. Eu escrevo meu melhor código quando estou sozinha com meus pensamentos e não olhando para uma caixa de bate-papo e falando em voz alta. Não há problema com isso. Esqueço assinaturas de métodos que usei mil vezes e cometo erros "bobos" em quase todas as sessões de <em>streaming</em>. Não é, com certeza, um ambiente produtivo e, ali, você não estará no seu melhor momento de produção.</p><p>Minha comunidade da Twitch nunca me julga por isso. Eles me ajudam muito. Eles entendem que sou multitarefa e são realmente ótimos em dar conselhos e sugestões pragmáticas. Às vezes, eles me socorrem. Em outras, eu tenho que explicar a eles por que a sugestão deles não funciona. É realmente como uma programação em duplas comum!</p><p>Acho que a abordagem 'de mostrar tudo, inclusive o problemático' nesse meio é um ponto forte, não uma fraqueza. Isso faz com que as pessoas consigam se relacionar melhor com você. Além disso, é importante mostrar que não existe o programador perfeito ou o código perfeito. Provavelmente, é um grande alívio para os novos programadores que assistem, além de uma lição de humildade para mim como programadora mais experiente.</p><h3 id="conclus-o"><strong>Conclusão</strong></h3><p>Se você está querendo começar a fazer programação ao vivo na Twitch, eu encorajo você a experimentá-la! Espero que este artigo tenha ajudado se você tem se perguntado por onde começar.</p><p>Se quiser se juntar a mim nos domingos, <a href="https://www.twitch.tv/noopkat" rel="noopener">siga meu canal na Twitch</a>. 🙂</p><p>Para encerrar, gostaria de fazer um agradecimento pessoal a <a href="https://twitter.com/mpjme" rel="noopener">Mattias Johansson</a>, por sua sabedoria e encorajamento no início de minha jornada como <em>streamer</em>. Ele foi incrivelmente generoso em seus conselhos, e o canal dele no YouTube, o <a href="https://www.youtube.com/channel/UCO1cgjhGzsSYb1rsB4bFe4Q" rel="noopener">FunFunFunction</a> é uma fonte contínua de inspiração.</p><p><strong>Atualização<strong>:</strong></strong> algumas pessoas têm me perguntado sobre meu teclado e sobre outras partes da minha estação de trabalho. <a href="https://gist.github.com/noopkat/5de56cb2c5917175c5af3831a274a2c8" rel="noopener">Aqui vai uma lista completa das coisas que eu uso</a> (em inglês). Agradeço o seu interesse!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Introdução a estruturas de dados: árvore binária de busca ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Kevin Turney Como combinar a eficiência de inserção de uma lista vinculada e a busca rápida de um array ordenado.  O que é uma árvore binária de busca? Vamos começar com a terminologia básica para que possamos falar a mesma língua e investigar conceitos relativos. Primeiramente, quais ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/introducao-a-estruturas-de-dados-arvore-binaria-de-busca/</link>
                <guid isPermaLink="false">6511866586ff8703fbd87d53</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gustavo Goulart Baptista ]]>
                </dc:creator>
                <pubDate>Tue, 11 Jun 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/0_gYtXwdbgInK7hI-u.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/data-structures-101-binary-search-tree-398267b6bff0/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Data Structures 101: Binary Search Tree</a>
      </p><p>Escrito por: Kevin Turney</p><h4 id="como-combinar-a-efici-ncia-de-inser-o-de-uma-lista-vinculada-e-a-busca-r-pida-de-um-array-ordenado-"><strong>Como combinar a eficiência de inserção de uma lista vinculada e a busca rápida de um array ordenado. </strong></h4><h3 id="o-que-uma-rvore-bin-ria-de-busca"><strong><strong>O que é uma </strong>á<strong>rvore </strong>b<strong>inária de </strong>b<strong>usca<strong>?</strong></strong></strong></h3><p>Vamos começar com a terminologia básica para que possamos falar a mesma língua e investigar conceitos relativos. Primeiramente, quais princípios definem a árvore binária de busca (em inglês, <em>Binary Search Tree ou BST)</em>?</p><blockquote>Observação: a partir daqui, usarei somente "BST" para facilitar.</blockquote><p>Uma BST é considerada uma estrutura de dados feita a partir de <strong>nós </strong>(em inglês <em>nodes</em>), assim como as listas encadeadas (em inglês, <em>linked lists –</em><strong> </strong><a href="https://medium.freecodecamp.org/data-structures-101-linked-lists-254c82cf5883">leia mais</a> no artigo em inglês). Esses nós podem ser nulos ou ter referências (encadear) para outros nós. Esses "outros" nós são nós filhos, chamados de nó esquerdo e nó direito. Nós tem <strong>valores </strong>e esses valores determinam quando eles serão alocados dentro da BST.</p><p>Da mesma maneira que ocorre com uma lista vinculada, cada nó é referenciado <strong>somente </strong>por um outro nó, seu próprio pai, exceto o nó originário ou raiz. Podemos dizer, então, que cada nó em uma BST é uma BST própria, pois ao seguirmos a árvore, logo abaixo, nós alcançamos outro nó que tem outros dois filhos, um esquerdo e um direito. Independentemente de onde formos, esse nó vai ter um nó direito e um esquerdo como filhos e assim por diante.</p><p>1. O nó esquerdo é sempre menor que seu pai.</p><p>2. O nó direito é sempre maior que seu pai.</p><p>3. Uma BST é considerada balanceada se cada nível da árvore está completamente preenchido com exceção do último nível. Nele, a árvore é preenchida da esquerda pra direita.</p><p>4. Uma BST perfeita é aquela que é tanto cheia como completa (todos os nós filhos estão no mesmo nível e cada nó tem um nó esquerdo e um direito)</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/2rTqYlcrnWtICedt131tDft0CmkzZaViExJX.jpg" class="kg-image" alt="2rTqYlcrnWtICedt131tDft0CmkzZaViExJX" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/2rTqYlcrnWtICedt131tDft0CmkzZaViExJX.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/2rTqYlcrnWtICedt131tDft0CmkzZaViExJX.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="970" loading="lazy"></figure><h3 id="aplica-es-teis-da-bst"><strong>Aplicações úteis da BST</strong></h3><p>Quais são os exemplos reais das BSTs? Árvores são comumente usadas em buscas, lógicas de jogos, tarefas de preenchimento automático e gráficos.</p><p>Velocidade. Como mencionado anteriormente, a BST é uma estrutura ordenada de dados. Após a inserção, os nós são colocados de maneira ordenada. Essa ordem herdada faz as buscas serem mais rápidas. Similarmente a busca binária (com um <em>array </em>que é ordenado), cortamos pela metade o número de dados para ordenar a cada iteração. Por exemplo, suponha que estamos buscando por um nó com um pequeno valor. A cada iteração, continuamos movendo à esquerda em direção ao nó buscado. Isso elimina a metade dos valores maiores automaticamente! </p><p>Assim como um <em>array</em>, o dado é guardado por referência. Ao adicionar para a estrutura de dados, criamos um grupo na memória e o conectamos a ele. Fazer isso é mais rápido que criar um <em>array </em>com mais espaços e só então inserir o dado do menor <em>array</em> para o novo e maior.</p><p>Para resumir, inserção, exclusão e busca são habilidades de destaque para as BSTs.</p><p>Agora que entendemos os princípios, os benefícios e os componentes básicos de uma BST, vamos implementar uma em javascript.</p><p>A API para BST contém o seguinte: <strong><strong>Insert, Contains, Get Min, Get Max, Remove Node, Check if Full, Is Balanced</strong></strong> e os tipos de Busca — <strong><strong>Depth First (preOrder, inOrder, postOrder), Breadth First Search</strong></strong> e, por fim, <strong><strong>Get Height</strong></strong>. Essa é uma API bem grande, vamos olhar uma seção de cada vez. </p><h3 id="implementa-o"><strong><strong><strong>Implementa</strong></strong>ção</strong></h3><p><strong>O <strong>construtor</strong></strong></p><p>A BST é feita de nós – e cada nó tem um valor.</p><pre><code>function Node(value){  
	this.value = value;
    this.left = null;
    this.right = null;
}</code></pre><p>O construtor da BST é criado a partir de um nó raiz.</p><pre><code>function BinarySearchTree() {
	this.root = null;
}</code></pre><pre><code>let bst = new BST();
let node = new Node();</code></pre><pre><code>console.log(node, bst); // Node { value: undefined, left: null, right: null } BST { root: null }</code></pre><p>Até agora, tudo vai bem.</p><h3 id="inser-o-insert-"><strong>Inserção (Insert)</strong></h3><pre><code>BinarySearchTree.prototype.insert = function(value){
	let node = new Node(value);
	if(!this.root) this.root = node;
	else{    
    	let current = this.root;
        while(!!current){
        	if(node.value &lt; current.value){
           		if(!current.left){
               		current.left = node;
                   	break;
               	}
        	   	current = current.left;
            }
            else if(node.value &gt; current.value){
            	if(!current.right){
                	current.right = node;
                   	break;
               	}
                current = current.right;
            } 
            else {
            	break;
            }
     	}
     }
     return this;
};</code></pre><pre><code>let bst = new BST();
bst.insert(25); // BST { root: Node { value: 25, left: null, right: null } }</code></pre><p>Vamos adicionar mais valores. </p><pre><code>bst.insert(40).insert(20).insert(9).insert(32).insert(15).insert(8).insert(27);</code></pre><pre><code>BST { root:  Node { value: 25, left: Node { value: 20, left: [Object], right: null }, right: Node { value: 40, left: [Object], right: null } } }</code></pre><p>Para uma visualização melhor, basta <a href="http://btv.melezinek.cz/binary-search-tree.html" rel="noopener">só clicar aqui</a>!</p><p>Vamos decifrar isso.</p><ol><li>Primeiramente, passamos um valor e criamos um nó</li><li>Observar se tem um nó raiz. Senão, configurar esse nó recém-criado para apontar para o nó raiz</li><li>Se existir um nó raiz, criamos uma variável declarada como "current" e configuramos esse valor para o nó raiz</li><li>Se o nó for recém-criado, node.value, for menor que o nó raiz, movemos o nó para a esquerda</li><li>Continuamos comparando esse node.value para os valores da esquerda.</li><li>Se o valor for bem menor e alcançarmos um ponto onde não existirem mais nós esquerdos, colocaremos esse item aqui.</li><li>Se o node.value é maior, repetiremos os mesmos passos acima exceto que em direção à direita.</li><li>Precisamos inserir um <em>break, </em>porque não há um contador de passos para terminar o laço.</li></ol><h3 id="cont-m-contains-"><strong>Contém (contains)</strong></h3><p>Essa abordagem é bem direta.</p><pre><code>BinarySearchTree.prototype.contains = function(value){
	let current = this.root;
    while(current){
    	if(value === current.value) return true;
        if(value &lt; current.value) current = current.left;
        if(value &gt; current.value) current = current.right;
    }
    return false;
};</code></pre><h3 id="obter-o-m-nimo-e-o-m-ximo-get-min-e-get-max-"><strong>Obter o mínimo e o máximo (Get Min e Get Max).</strong></h3><p>Siga para a esquerda para achar o menor valor e para a direita para o maior valor.</p><pre><code>BinarySearchTree.prototype.getMin = function(node){
	if(!node) node = this.root;
    while(node.left) {
    	node = node.left;
    }
    return node.value
};</code></pre><pre><code>BinarySearchTree.prototype.getMax = function(node){
	if(!node) node = this.root;
    while(node.right) {
    	node = node.right;
    }
    return node.value;
};</code></pre><h3 id="remo-o-removal-"><strong>Remoção (removal)</strong></h3><p>Remover um nó é uma operação mais complicada, pois os nós tem que ser reordenados para que as propriedades da BST sejam mantidas. Existe um caso onde um nó tem apenas um filho e um caso onde o nó tem tanto o filho da direita como da esquerda. Usaremos a uma função para nos ajudar a fazer o trabalho pesado. </p><pre><code>BinarySearchTree.prototype.removeNode = function(node, value){
	if(!node){
    	return null;
    }
    if(value === node.value){ // sem filhos
    if(!node.left &amp;&amp; !node.right) return null; // um filho e é o da direita
    if(!node.left) node.right;// um filho e é o da esquerda
    if(!node.right) node.left;  // dois filhos
    const temp = this.getMin(node.right);
    node.value = temp;
    node.right = this.removeNode(node.right, temp);
    return node;
    } else if(value &lt; node.value) {
    	node.left = this.removeNode(node.left, value);
        return node;
   } else  {
      	node.right = this.removeNode(node.right, value);
        return node;
   }
};</code></pre><pre><code>BinarySearchTree.prototype.remove = function(value){
	this.root = this.removeNode(this.root, value);
};</code></pre><p>Funciona assim…</p><p>Diferente de <em>deleteMin </em>e <em>deleteMax</em>, onde apenas cruzamos todo o caminho para a direita ou esquerda e pegamos o último valor, aqui, temos que retirar o nó e substituí-lo por algo. Essa solução foi desenvolvida em 1962 por T. Hibbard. Contamos com o caso onde podemos excluir um nó filho ou nenhum, esse é o caso mais fácil. Sem filhos, sem problemas. Se o filho estiver presente é só movê-lo para cima.</p><p>Entretanto, quando temos um nó para ser removido que tem dois filhos, qual deles fará a substituição? Certamente, não podemos mover o filho maior para baixo, então o que fazemos é trocá-lo pelo seu sucessor. Temos que buscar o menor filho à direita que é maior que o filho esquerdo.</p><ol><li>Crie uma variável temporária e guarde o menor nó na sua direita. Isso cumprirá o requisito de que a propriedade que tem o valor da esquerda, ainda assim, é menor e os valores da esquerda que ainda são maiores;</li><li>Reinicialize o valor do nó essa variável temporária; </li><li>Exclua o nó direito;</li><li>Compare os valores na esquerda e na direita e determine qual será o valor atribuído.</li></ol><p>Acho que uma imagem ilustrará isso melhor:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/cEcyXZpZvRln6p7jzJq08lOJsORH6yA7Rd0T.jpg" class="kg-image" alt="cEcyXZpZvRln6p7jzJq08lOJsORH6yA7Rd0T" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/cEcyXZpZvRln6p7jzJq08lOJsORH6yA7Rd0T.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/cEcyXZpZvRln6p7jzJq08lOJsORH6yA7Rd0T.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="883" loading="lazy"></figure><h3 id="busca-search-"><strong>Busca (search)</strong></h3><p>Existem dois tipo de busca: <em>Depth First</em> e <em>Breadth First</em>. <em>Breadth First</em> (busca por largura, em português) é simplesmente quando você para a cada nível ao descer pela árvore. Seria algo parecido com isso: começamos na raiz, então filho esquerdo e depois filho direito. Passamos para o próximo nível, filhos esquerdos e filhos direitos. Pense nisso como se estivesse se movendo horizontalmente. Empregamos, até diria que simulamos, uma fila para ajudar a ordenar o processo. Passamos a função, porque, muitas vezes, queremos operar em um valor.</p><pre><code>BinarySearchTree.prototype.traverseBreadthFirst = function(fn) {
	let queue = [];
    queue.push(this.root);
    while(!!queue.length) {
    	let node = queue.shift();
        fn(node);
        node.left &amp;&amp; queue.push(node.left);
        node.right &amp;&amp; queue.push(node.right);
    }
}</code></pre><p>A busca<em> Depth First</em> (busca por profundidade, em português) envolve seguir para baixo da BST de uma maneira específica, ou seja: preOrder, inOrder, ou postOrder (pré-ordem, na ordem ou pós-ordem, respectivamente). Explicarei as diferenças em breve. </p><p>Em termos de código, temos uma função básica, traverseDepthFirst, e passamos uma função e um método. Outra vez, a função implica que queremos fazer algo com o valor no percurso, enquanto o método é o tipo de busca que estamos tentando realizar. Na traverseDepthFirst, temos uma alternativa, a busca preOrder, pré-selecionada.</p><p>Agora, qual a diferença entre elas? Primeiro, enviamos a função inOrder. Deveria ser autoexplicativo, mas não é. Estamos querendo dizer em ordem de inserção, em ordem do maior para o menor, ou do menor para o maior? Eu quero apenas que você tenha isso em mente de antemão. Nesse caso, sim, quer dizer do menor para o maior. </p><p><strong><strong>preOrder</strong></strong> pode ser pensado como <strong><strong>Pa</strong>i<strong>, </strong>Filho Esquerdo, Filho Direito. </strong></p><p><strong><strong>postOrder</strong></strong>, por outro lado, seria como <strong>Filho Esquerdo, Filho Direito, Pai.</strong></p><pre><code>BinarySearchTree.prototype.traverseDFS = function(fn, method){
	let current = this.root;
    if(!!method) this[method](current, fn);
    else this._preOrder(current, fn);
};</code></pre><pre><code>BinarySearchTree.prototype._inOrder = function(node, fn){
	if(!!node){
    	this._inOrder(node.left, fn);
	    if(!!fn) fn(node);
    	this._inOrder(node.right, fn);
    }
};</code></pre><pre><code>BinarySearchTree.prototype._preOrder = function(node, fn){
	if(node){ 
    	if(fn) fn(node);
    	this._preOrder(node.left, fn);
    	this._preOrder(node.right, fn);
    }
};</code></pre><pre><code>BinarySearchTree.prototype._postOrder = function(node, fn){
	if(!!node){ 
    		this._postOrder(node.left, fn);
    		this._postOrder(node.right, fn);
        	if(!!fn) fn(node);
    }
};</code></pre><h3 id="checar-se-a-bst-est-cheia"><strong>Checar se a <strong><strong>BST </strong></strong>está cheia</strong></h3><p>Lembre-se do que comentamos antes: uma BST está cheia se cada nó existente na árvore tiver ou Zero ou dois filhos.</p><pre><code>// uma BST está cheia se cada nó tiver ou zero ou dois filhos (nenhum nó pode ter apenas um filho)</code></pre><pre><code>BinarySearchTree.prototype.checkIfFull = function(fn){
	let result = true;
    this.traverseBFS = (node) =&gt; {
    	if(!node.left &amp;&amp; !node.right) result = false;
        else if(node.left &amp;&amp; !node.right) result = false;
    }
    return result;
};</code></pre><h3 id="obter-a-altura-da-bst"><strong>Obter a altura da BST</strong></h3><p>O que significa obter a altura de uma árvore? Por que é importante? Aqui é onde a <strong>Complexidade de Tempo</strong> (também conhecida como Big O) aparece. Operações básicas são proporcionais ao tamanho da árvore. Então, se lembrarmos do que foi dito antes, ao buscar por um valor específico, o número de operações que temos a fazer é reduzido a metade a cada etapa.</p><p>Isso significa que temos um pão e vamos cortá-lo a metade, depois dividir essa metade em outros dois pedaços e continuamos fazendo isso até termos exatamente o pedaço de pão que queremos.</p><p>Em ciência da computação, chamamos isso de O(log n). Começamos com algum tipo de tamanho de entrada e, com o tempo, o tamanho fica melhor (mais achatado). Uma busca linear direta é denotada como O(n). Conforme o tamanho da entrada aumenta, também aumenta o tempo para executar as operações. O(n), conceitualmente, é uma linha de 45° começando da origem zero em um gráfico se movendo para a direita. A escala horizontal representa o tamanho de uma entrada e a escala vertical representa o tempo levado para completá-la.</p><p>Tempo constante é O(1). Não importa o tamanho da entrada, seja grande ou pequena, a operação leva exatamente o mesmo tempo. Por exemplo, push() e pop() de um array possuem tempo constante, assim como obter o valor em uma HashTable.</p><p>Eu vou explicar mais sobre isso em um artigo futuro, mas já quis adiantar um pouco as coisas agora.</p><p><strong>De volta à altura.</strong></p><p>Temos uma função recursiva. Nosso caso base é: <strong>"se não temos um nó, então começamos em <strong>this.root</strong>"<strong><em><em>.</em></em></strong></strong> Isso implica que podemos começar em valores menores na árvore e obter árvores com subalturas.</p><p>Então se passamos em this.root para começar, recursivamente movemos para baixo e adicionamos funções que chamarão a pilha de execução (em inglês <em>execution stack</em>). Quando alcançamos o fundo, a pilha é preenchida e, então, a chamada é executada e comparamos as alturas da esquerda e da direita e incrementamos um.</p><pre><code>BinarySearchTree.prototype._getHeights = function(node){
	if(!node) return -1;
    let left = this._getHeights(node.left);
    let right = this._getHeights(node.right);
    return Math.max(left, right) + 1;
};</code></pre><pre><code>BinarySearchTree.prototype.getHeight = function(node){
	if(!node) node = this.root;
    return this._getHeights(node);
};</code></pre><h3 id="por-ltimo-is-balanced-est-balanceada-"><strong>Por último, Is Balanced (está balanceada)</strong></h3><p>O que estamos fazendo aqui é observar se a árvore está preenchida em cada nível, e se &nbsp;no último nível ela está preenchida da esquerda para a direita.</p><pre><code>BinarySearchTree.prototype._isBalanced = function(node){
	if(!node) return true;
    let heightLeft = this._getHeights(node.left);
    let heightRight = this._getHeights(node.right);
    let diff = Math.abs(heightLeft — heightRight);
    if(diff &gt; 1) return false;
    else return this._isBalanced(node.left) &amp;&amp;    this._isBalanced(node.right);
};</code></pre><pre><code>BinarySearchTree.prototype.isBalanced = function(node){
	if(!node) node = this.root;
    return this._isBalanced(node);
};</code></pre><h3 id="imprimir-a-rvore-print-"><strong>Imprimir a árvore (print)</strong></h3><p>Use isso para visualizar todos os métodos que você vê, especialmente travessias <em>depth first</em> e <em>breadth first</em>.</p><pre><code>BinarySearchTree.prototype.print = function() {
	if(!this.root) {
    	return console.log('Nó raiz não encontrado');
    }
    let newline = new Node('|');
    let queue = [this.root, newline];
    let string = ''; 
    while(queue.length) {
    	let node = queue.shift();
        string += node.value.toString() + ' ';
        if(node === newline &amp;&amp; queue.length) queue.push(newline);
        if(node.left) queue.push(node.left);
        if(node.right) queue.push(node.right);
     }
     console.log(string.slice(0, -2).trim());
};</code></pre><p><strong>Nosso amigo, o c<strong>onsole.log! </strong>Sinta-se livre para brincar com ele e experimentar. </strong></p><pre><code>const binarySearchTree = new BinarySearchTree();
binarySearchTree.insert(5);
binarySearchTree.insert(3);</code></pre><pre><code>binarySearchTree.insert(7);
binarySearchTree.insert(2);
binarySearchTree.insert(4);
binarySearchTree.insert(4);
binarySearchTree.insert(6);
binarySearchTree.insert(8);
binarySearchTree.print(); // =&gt; 5 | 3 7 | 2 4 6 8</code></pre><pre><code>binarySearchTree.contains(4);</code></pre><pre><code>//binarySearchTree.printByLevel(); // =&gt; 5 \n 3 7 \n 2 4 6 8
console.log('--- DFS inOrder');</code></pre><pre><code>binarySearchTree.traverseDFS(function(node) {
	console.log(node.value);
}, '_inOrder'); // =&gt; 2 3 4 5 6 7 8</code></pre><pre><code>console.log('--- DFS preOrder');</code></pre><pre><code>binarySearchTree.traverseDFS(function(node) {
	console.log(node.value);
}, '_preOrder'); // =&gt; 5 3 2 4 7 6 8</code></pre><pre><code>console.log('--- DFS postOrder');</code></pre><pre><code>binarySearchTree.traverseDFS(function(node) {
	console.log(node.value);
}, '_postOrder'); // =&gt; 2 4 3 6 8 7 5</code></pre><pre><code>console.log('--- BFS');</code></pre><pre><code>binarySearchTree.traverseBFS(function(node) {
	console.log(node.value);
}); // =&gt; 5 3 7 2 4 6 8</code></pre><pre><code>console.log('min é 2:', binarySearchTree.getMin()); // =&gt; 2</code></pre><pre><code>console.log('máx é 8:', binarySearchTree.getMax()); // =&gt; 8</code></pre><pre><code>console.log('árvore contém 3 é true:', binarySearchTree.contains(3)); // =&gt; true</code></pre><pre><code>console.log('árvore contém 9 é false:', binarySearchTree.contains(9)); // =&gt; false</code></pre><pre><code>// console.log('altura da árvore é 2:', binarySearchTree.getHeight()); // =&gt; 2</code></pre><pre><code>console.log('árvore balanceada é true:', binarySearchTree.isBalanced(),'line 220'); // =&gt; true</code></pre><pre><code>binarySearchTree. remove(11); // remove o nó inexistente</code></pre><pre><code>binarySearchTree.print(); // =&gt; 5 | 3 7 | 2 4 6 8</code></pre><pre><code>binarySearchTree.remove(5); // remove 5 e 6 sobe</code></pre><pre><code>binarySearchTree.print(); // =&gt; 6 | 3 7 | 2 4 8</code></pre><pre><code>console.log(binarySearchTree.checkIfFull(), 'deve ser verdadeiro');</code></pre><pre><code>var fullBSTree = new BinarySearchTree(10);</code></pre><pre><code>fullBSTree.insert(5).insert(20).insert(15).insert(21).insert(16).insert(13);</code></pre><pre><code>console.log(fullBSTree.checkIfFull(), 'should be true');</code></pre><pre><code>binarySearchTree.remove(7); // remove 7 e 8 sobe</code></pre><pre><code>binarySearchTree.print(); // =&gt; 6 | 3 8 | 2 4</code></pre><pre><code>binarySearchTree.remove(8); // remove 8 e a árvore fica desbalanceada</code></pre><pre><code>binarySearchTree.print(); // =&gt; 6 | 3 | 2 4</code></pre><pre><code>console.log('árvore balanceada é false:', binarySearchTree.isBalanced()); // =&gt; true</code></pre><pre><code>console.log(binarySearchTree.getHeight(),'altura é 2')</code></pre><pre><code>binarySearchTree.remove(4);</code></pre><pre><code>binarySearchTree.remove(2);</code></pre><pre><code>binarySearchTree.remove(3);</code></pre><pre><code>binarySearchTree.remove(6);</code></pre><pre><code>binarySearchTree.print(); // =&gt; 'Não foi encontrado o nó raiz'</code></pre><pre><code>//binarySearchTree.printByLevel(); // =&gt; 'Não foi encontrado o nó raiz'</code></pre><pre><code>console.log('altura da árvore é -1:', binarySearchTree.getHeight()); // =&gt; -1</code></pre><pre><code>console.log('árvore balanceada é true:', binarySearchTree.isBalanced()); // =&gt; true</code></pre><pre><code>console.log('---');</code></pre><pre><code>binarySearchTree.insert(10);</code></pre><pre><code>console.log('altura da árvore é 0:', binarySearchTree.getHeight()); // =&gt; 0</code></pre><pre><code>console.log('ávroe balanceada é true:', binarySearchTree.isBalanced()); // =&gt; true</code></pre><pre><code>binarySearchTree.insert(6);</code></pre><pre><code>binarySearchTree.insert(14);</code></pre><pre><code>binarySearchTree.insert(4);</code></pre><pre><code>binarySearchTree.insert(8);</code></pre><pre><code>binarySearchTree.insert(12);</code></pre><pre><code>binarySearchTree.insert(16);</code></pre><pre><code>binarySearchTree.insert(3);</code></pre><pre><code>binarySearchTree.insert(5);</code></pre><pre><code>binarySearchTree.insert(7);</code></pre><pre><code>binarySearchTree.insert(9);</code></pre><pre><code>binarySearchTree.insert(11);</code></pre><pre><code>binarySearchTree.insert(13);</code></pre><pre><code>binarySearchTree.insert(15);</code></pre><pre><code>binarySearchTree.insert(17);</code></pre><pre><code>binarySearchTree.print(); // =&gt; 10 | 6 14 | 4 8 12 16 | 3 5 7 9 11 13 15 17</code></pre><pre><code>binarySearchTree.remove(10); // remove 10 e 11 sobe</code></pre><pre><code>binarySearchTree.print(); // =&gt; 11 | 6 14 | 4 8 12 16 | 3 5 7 9 x 13 15 17</code></pre><pre><code>binarySearchTree.remove(12); // remove 12 e 13 sobe</code></pre><pre><code>binarySearchTree.print(); // =&gt; 11 | 6 14 | 4 8 13 16 | 3 5 7 9 x x 15 17</code></pre><pre><code>console.log('árvore balanceada é true:', binarySearchTree.isBalanced()); // =&gt; true</code></pre><pre><code>//console.log('árvore balanceada otimizada é true:', binarySearchTree.isBalancedOptimized()); // =&gt; true</code></pre><pre><code>binarySearchTree.remove(13); // remove 13 e 13 não tem filhos - nada acontece</code></pre><pre><code>binarySearchTree.print(); // =&gt; 11 | 6 14 | 4 8 x 16 | 3 5 7 9 x x 15 17</code></pre><pre><code>console.log('árvore balanceada é false:', binarySearchTree.isBalanced()); // =&gt; false</code></pre><h3 id="complexidade-de-tempo"><strong>Complexidade de tempo</strong></h3><p>1. Inserção O(log n)<br>2. Remoção O(log n)<br>3. Busca O(log n)</p><p>Uau, isso foi realmente muita informação. Espero que as explicações tenham sido claras e introdutórias o máximo possível. Outra vez, escrever me ajuda a solidificar conceitos e, como dizia Richard Feynman: "Quando uma pessoa ensina, duas pessoas aprendem."</p><h3 id="recursos"><strong>Recursos</strong></h3><p>Estes são recursos ótimos para visualização (em inglês):</p><ul><li><a href="https://www.cs.usfca.edu/~galles/visualization/Algorithms.html" rel="noopener"><strong><strong>Data Structure Visualization</strong></strong></a></li><li><a href="http://btv.melezinek.cz/binary-search-tree.html" rel="noopener"><strong><strong>BinaryTreeVisualiser - Binary Search Tree</strong></strong></a></li><li><a href="https://visualgo.net/en/bst?slide=1" rel="noopener"><strong><strong>VisuAlgo - Binary Search Tree, AVL Tree</strong></strong></a></li><li><a href="http://www.bigocheatsheet.com/" rel="noopener"><strong><strong>Big-O Algorithm Complexity Cheat Sheet (Know Thy Complexities!) </strong></strong></a></li><li><a href="https://algs4.cs.princeton.edu/home/" rel="noopener"><strong><strong>Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne</strong></strong></a></li><li><a href="https://en.wikipedia.org/wiki/Binary_search_tree" rel="noopener"><strong><strong>Binary search tree - Wikipedia</strong></strong></a></li></ul><p>Versão da Wikipédia em português: <a href="https://pt.wikipedia.org/wiki/%C3%81rvore_bin%C3%A1ria_de_busca">Árvore binária de busca</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como eu conclui todo o currículo do freeCodeCamp em 9 meses enquanto trabalhava em tempo integral ]]>
                </title>
                <description>
                    <![CDATA[ Durante o ano passado, terminei o currículo inteiro do freeCodeCamp [https://www.freecodecamp.org/] enquanto trabalhava em tempo integral como professora. Neste artigo, vou descrever como consegui fazer isso. Particularmente, quero falar sobre como organizei meu tempo e que material complementar usei. Histórico Primeiro, vamos falar do que há por trás disso. Eu ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-eu-conclui-todo-o-curriculo-do-freecodecamp-em-9-meses-enquanto-trabalhava-em-tempo-integral/</link>
                <guid isPermaLink="false">6630106c28986303fd72607e</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Tue, 30 Apr 2024 01:25:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/0_o0GxOVsLogUdGl9u.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-i-finished-the-entire-freecodecamp-curriculum-in-9-months-while-working-full-time-f3b10d04e02e/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How I finished the entire freeCodeCamp curriculum in 9 months while working full time</a>
      </p><p>Durante o ano passado, terminei o currículo inteiro do <a href="https://www.freecodecamp.org/">freeCodeCamp</a> enquanto trabalhava em tempo integral como professora. Neste artigo, vou descrever como consegui fazer isso. Particularmente, quero falar sobre como organizei meu tempo e que material complementar usei.</p><h4 id="hist-rico"><strong><strong>Histórico</strong></strong></h4><p>Primeiro, vamos falar do que há por trás disso. Eu não era completamente nova na programação. Cresci em uma pequena empresa de tecnologia.</p><p>Meu pai fundou sua própria empresa antes de eu nascer, onde eles realizavam diferentes atividades dentro da tecnologia, como consertar computadores, configurar conexões e redes de internet para outras empresas, ministrar cursos de informática e construir aplicações administrativos para empresas. Era uma cidade pequena, então eles eram basicamente os "caras da tecnologia" para toda a cidade.</p><p>Os escritórios da empresa eram em nossa casa. Então, eu literalmente cresci entre computadores e pessoas que gostavam deles. Comecei a brincar com o Visual Basic quando criança (um dos caras da empresa me ensinou a usá-lo) e passei todo o meu tempo livre on-line, conversando com colegas nerds.</p><p>Quando eu tinha uns 12 anos, um desses nerds me enviou por e-mail um manual de desenvolvimento para web (um arquivo .txt enorme que, basicamente, tratava de HTML) e eu o usei para construir meu próprio site. Ele tinha até um daqueles contadores de visita bacanas.</p><p>Eu o hospedei na Geocities, consegui um URL curto gratuito e o listei no Yahoo e no AltaVista (esses eram os maiores na época).</p><p>Depois disso, a vida aconteceu e eu desisti completamente da ideia de ser programadora, pois as circunstâncias exigiam uma abordagem mais "realista". Não vou entrar em detalhes agora, mas tive que desistir de estudar e conseguir um emprego.</p><p>Continuei vivendo minha vida. Eu construía sites, aqui e ali, para os clientes do meu pai. No fim, decidi começar a ensinar inglês, que era algo que veio fácil para mim e esqueci tudo sobre desenvolvimento para a web. Foi quando chegou o ano de 2016.</p><h4 id="como-decidi-mudar-de-carreira"><strong><strong>Como decidi mudar de carreira</strong></strong></h4><p>Adoro ensinar. É uma profissão gratificante, interessante e divertida, mas tem seus pontos negativos. No início, tudo parecia um desafio. Porém, depois de tantos anos fazendo isso, comecei a sentir que não tinha propósito, que eu não estava mais crescendo ou aprendendo.</p><p>Eu estava me sentindo presa. Era como se meu trabalho fosse exatamente o mesmo ano após ano. Eu estava apenas seguindo em frente. Também não havia muitas oportunidades para realocação, algo que se tornou muito importante para mim mais tarde.</p><p>Em 2013, conheci meu marido e, no ano seguinte, fizemos uma viagem de três meses para a Europa mochilando, mas isso vale um outro artigo totalmente diferente. Basicamente, tínhamos um orçamento extremamente baixo e tivemos uma experiência incrível. Amamos a Europa e decidimos que voltaríamos para outra longa viagem.</p><p>O tempo passou, fizemos outras coisas e eu encontrei a Codecademy e comecei a brincar com ela e com a ideia de me tornar uma desenvolvedora em tempo integral. Eu já tinha alguma experiência construindo sites apenas com HTML e CSS, mas sem JavaScript. Eu estava lendo muitas histórias de sucesso on-line, mas ainda não considerava uma carreira real, nem de longe.</p><p>Enquanto isso, estávamos planejando a próxima viagem longa, economizando dinheiro, planejando e assim por diante. Eu estava trabalhando como tradutora freelancer cada vez mais, muito envolvida com a minha carreira, traduzindo coisas legais como romances e poesias. Chegou 2017 e fomos para a Europa novamente, desta vez por dois meses.</p><p>Lá, conhecemos vários desenvolvedores. Foi uma loucura. Cada um dos <em>couch surfers</em> que conhecemos parecia estar em TI de alguma forma, seja como gerente de produto de software, desenvolvedor, testador e assim por diante. Todos eles nos incentivaram a entrar na tecnologia. Nessa altura, já tínhamos decidido que queríamos nos mudar para a Europa. Por isso, muitos deles diziam: "Vocês podem arranjar emprego aqui. Os desenvolvedores são procurados por aqui e precisamos de muitos deles."</p><p>Antes de a viagem terminar, tomamos a decisão de nos inscrever para um certificado técnico de 2 anos em uma universidade técnica recém-fundada perto de nossa cidade natal. O programa era principalmente Java. Então, quando voltamos, começamos um curso de Java na Cousera. O primeiro módulo era, na verdade, um curso de JavaScript. Foi como ficamos viciados em JavaScript quase que imediatamente.</p><p>Enquanto aprendíamos JavaScript, esperávamos o início do ano letivo, em março de 2018. Foram apenas 50 vagas para a Universidade, então nos dedicamos e aprendemos de antemão. Fomos, fizemos provas, passamos em cursos e depois tivemos que esperar até que eles decidissem. Obtivemos as notas mais altas entre todos os candidatos, mas essas notas não fizeram diferença. As vagas seriam atribuídas por meio de um sistema de sorteio. Meu marido entrou e eu fiquei de fora.</p><p>Ele decidiu que preferia aprender sozinho. Não estava mais tão interessado em Java porque estava viciado em JavaScript. Começamos, então, a aprender por conta própria.</p><p>Começamos com a Codecademy, mas era muito "manual" para nós (não tínhamos contas Premium). Em algum lugar, lemos sobre o freeCodeCamp. Começamos, daí, muito lentamente no início (o primeiro certificado levou meses para ser obtido – admito que, no meio do currículo, ele foi alterado e eu joguei meu laptop longe e tive que consertá-lo). Depois que as férias de verão terminaram e eu voltei a trabalhar em tempo integral, as coisas ficaram difíceis.</p><h4 id="trabalhando-em-tempo-integral-e-fazendo-os-cursos-do-freecodecamp-a-toda-velocidade"><strong><strong>Trabalhando em tempo integral e fazendo os cursos do <strong>freeCodeCamp a</strong> toda velocidade</strong></strong></h4><p>Não foi fácil, não vou mentir. Ajudou que a maioria dos meus amigos e conhecidos não mora perto de mim, e eu moro em uma cidade pequena que não oferece muitas oportunidades de entretenimento. Nesse sentido, a programação foi um salva-vidas. Eu tinha algo divertido e viciante para fazer. Assim, eu pudematar horas de tédio com isso.</p><p>Isso ajudou muito ao lidar com a quantidade de horas que eu gastava fazendo trabalho mental (ensinando e estudando).</p><p>O primeiro certificado demorou meses, em parte porque eu estava esperando para entrar na Universidade e em parte porque eu estava trabalhando 10 horas por dia nos primeiros 3 meses do ano letivo.</p><p>Infelizmente, eu não podia simplesmente largar meu emprego e estudar em tempo integral, já que eu precisava pagar as contas. Foi quando precisei ficar muito boa em 3 coisas:</p><ol><li>Gestão do tempo</li><li>Disciplina</li><li>Organização</li></ol><h4 id="gest-o-do-tempo"><strong><strong>Gestão do tempo</strong></strong></h4><p>Eu começava a trabalhar às 7h. Então, comecei a levantar às 4h30 na maioria dos dias. Começava o dia com desafios freeCodeCamp e café. Às vezes, eu também lia um livro ou fazia outros tutoriais, dependendo do que eu estava trabalhando no momento. Também estudava durante o horário de almoço e depois do trabalho, mas aceitei o fato de não ser tão produtiva durante a semana por causa do trabalho. Então, durante a semana, fazia principalmente desafios curtos, leitura e assim por diante. Eu trabalhava em projetos nos finais de semana, feriados e no meu tempo livre.</p><p>Se eu tivesse 30 minutos, eu lia 30 minutos. Se eu tivesse 15, eu estudava por 15 minutos. Usei todos os momentos livres do meu dia para estudar.</p><p>Aos domingos, eu preparava a maior parte das minhas refeições da semana para não ter que gastar tempo cozinhando e não ter que acabar comendo coisas não saudáveis. Também planejei e reuni tudo o que precisava para trabalhar durante a semana, para não precisar gastar tempo extra além do horário normal de trabalho.</p><p>Felizmente, depois de junho, minha jornada de trabalho foi reduzida de 10 a 12 horas para 8. Eu estava trabalhando em um horário normal e foi aí que comecei a pegar o ritmo.</p><h4 id="disciplina"><strong><strong><strong>Disciplin</strong>a</strong></strong></h4><p>Você vai ter que estudar mesmo nos dias em que não tiver vontade. Aqui é onde a motivação também desempenha um grande papel, mas a disciplina é importante – especialmente se você é como eu e se distrai muito com mídias sociais e vídeos de gatos.</p><p>A melhor dica que posso dar para você para combater a tentação de ler artigos on-line é esta: se você vier com uma pergunta em sua cabeça como "como os aviões voam?" (que geralmente é o tipo de pergunta que me deixa levar e me suga por 30 minutos), anote em algum lugar e prometa a si mesmo que você pode ler tudo sobre isso depois de terminar o que está fazendo.</p><p>Em 99% das vezes, você não vai se importar mais, porque essas perguntas só aparecem em seu cérebro porque ele quer se distrair. Siga em frente e você vai vencer as distrações.</p><p>Outro aspecto da disciplina é ter que escolher o estudo em detrimento de outras coisas. Essa é a parte não tão divertida. Tive que desistir de muitas, muitas coisas que gostava para favorecer os estudos, e mal posso esperar para poder voltar a elas. Eu fiz isso apenas porque eu queria me tornar uma desenvolvedora o mais rápido possível (veja Motivação abaixo), mas mesmo que você não esteja com pressa como eu, você pode achar que gasta muito tempo fazendo coisas que, mesmo que sejam gostosas e agradáveis, ocupam muito do seu tempo.</p><blockquote>Você terá de priorizar e fará escolhas difíceis.</blockquote><h4 id="motiva-o"><strong><strong><strong>Motiva</strong>ção</strong></strong></h4><p>Eu tinha um motivador muito forte que era me tornar um desenvolvedor e me mudar para a Europa. Esse foi meu objetivo por muito, muito tempo. Cheguei ao ponto de ficar frustrada por não estar conseguindo. Todos os meus amigos saíram da cidade, praticamente não tenho família aqui, me senti isolada e queria ir embora.</p><p>Foi isso que me impulsionou. Parecia um fogo debaixo dos meus pés, eu sentia que não tinha escolha. Você precisa de uma forte motivação para fazer mudanças radicais. Eu não sei vocês, mas eu sou uma pessoa do tipo "não conserte o que não está quebrado". Então, é muito difícil me fazer fazer as coisas apenas por fazê-las.</p><p>Meus hobbies são todos muito práticos e produtivos: jardinagem, yoga, culinária. Eu preciso ter um motivo para fazê-los (eu quero vegetais grátis, minhas costas doem, estou com fome). Se você é parecido ou parecida comigo, vai precisar encontrar uma motivo para seguir em frente.</p><p>Passe algum tempo pensando sobre isso, o que exatamente você quer realizar terminando o freeCodeCamp? O que você quer mudar ou obter em sua vida pessoal através disso?</p><h4 id="o-curr-culo-e-os-recursos-complementares"><strong><strong>O<strong> </strong>currículo e os recursos complementares</strong></strong></h4><p>A seguir estão alguns dos recursos suplementares que usei na minha jornada com o freeCodeCamp. Tenha em mente que esta não é uma lista exaustiva porque eu consultei demais o Google – e que alguns dos cursos que eu menciono não são gratuitos.</p><p><strong>Design responsivo para a <strong>Web:</strong></strong> essa era a parte com a qual eu já tinha alguma experiência, então foi fácil e divertido. Utilizei alguns recursos complementares, especialmente para o Flexbox. Meu lugar favorito para isso é o <a href="https://internetingishard.netlify.app/">Interneting is hard</a> (em inglês).</p><p><strong>Algoritmos e estruturas de dados em <strong>JavaScript:</strong></strong> uma vez que cheguei aos módulos de JavaScript fiquei viciada. Foi tudo muito divertido, aprendi muito e estava ansiosa para colocar tudo isso em prática.</p><p>Para essa seção usei livros, principalmente. Eu já tinha feito muitos exercícios com o freeCodeCamp, mas eu precisava de mais no formato de explicações. O livro Beginning JavaScript traz toneladas de exercícios também.</p><ul><li><a href="https://www.amazon.co.uk/Beginning-JavaScript-5th-Jeremy-McPeak/dp/1118903331" rel="noopener">Beginning JavaScript 5th edition</a></li><li><a href="https://github.com/getify/You-Dont-Know-JS" rel="noopener">You Don’t Know JS</a></li><li><a href="https://www.coursera.org/learn/duke-programming-web" rel="noopener">Programming Foundations with JavaScript, HTML and CSS</a></li><li><a href="https://developer.mozilla.org/bm/docs/Web/JavaScript" rel="noopener">Documentação do JavaScript</a></li></ul><p>Quando cheguei a essa seção, também entrei no programa Summer of Code do <a href="https://1millionwomentotech.com/" rel="noopener">1 Million Women to Tech</a> (1MWTT). Aprendi Python básico e JavaScript do básico ao avançado, o que ajudou muito, principalmente com Promises.</p><p>Aprender Python também me ajudou a reforçar alguns conceitos básicos de programação. Eu recomendo seriamente que, quando você se sentir confiante com JavaScript, tente uma nova linguagem, apenas seus conceitos básicos. Você ficará muito mais confortável depois de saber como fazer a mesma coisa com ferramentas diferentes.</p><p><strong><strong>Frameworks</strong> do <strong>JavaScript:</strong></strong> esta seção também foi ótima, pois me deu uma base em React e Redux. Eu já estava fazendo um curso de React na <a href="https://www.udemy.com/" rel="noopener">Udemy</a>, chamado <a href="https://www.udemy.com/react-the-complete-guide-incl-redux/" rel="noopener">React 16.6 - The Complete Guide (including React Router &amp; Redux)</a> (curso em inglês).</p><p>Recomendo esse curso e outros cursos do mesmo autor. Ele é incrivelmente minucioso e suas explicações são incríveis. Esse foi um dos poucos cursos da Udemy em que eu realmente acompanhei o projeto que ele faz: normalmente assisto os vídeos e aplico os princípios em tudo o que estou trabalhando.</p><p>Na 1millionwomentotech, tivemos uma semana do React, que usava principalmente o React Native, então comecei a brincar com isso. Nessa altura também comecei a trabalhar no meu projeto paralelo com o meu marido, que decidimos que seria um PWA com o React.</p><p>Não posso enfatizar o quanto é importante construir algo próprio do zero. Aprendi muito mais em algumas semanas construindo nossa aplicação do que aprendi com qualquer curso ou tutorial.</p><p><strong><strong>APIs </strong>e m<strong>icro</strong>s<strong>servi</strong>ço<strong>s:</strong></strong> esta seção foi uma grande revelação para mim e mudou tudo. Até esse módulo, eu tinha certeza de que queria ser uma desenvolvedora de front-end, mas, depois de aprender Node.js, comecei a pensar em ser uma desenvolvedora back-end ou Full Stack. Criar APIs é muito divertido – e você vê os resultados rapidamente. Comecei a construir meus primeiros pequenos projetos Full Stack e fiquei muito animada.</p><p>Alguns dos recursos que utilizei (em inglês):</p><ul><li><a href="https://www.udemy.com/the-complete-nodejs-developer-course-2/" rel="noopener">The Complete Node.js Developer Course (2nd Edition)</a></li><li><a href="https://node-girls.gitbook.io/intro-to-express" rel="noopener">Node Girls Intro to Backend Development with Express</a></li><li><a href="https://nodejs.org/en/docs/" rel="noopener">Documentação do Node</a></li><li><a href="https://expressjs.com/" rel="noopener">Documentação do Express</a></li><li><a href="https://nodeschool.io/" rel="noopener">NodeSchool</a></li><li><a href="https://frontendmasters.com/courses/node-js/" rel="noopener">Introduction to Node.js</a></li><li><a href="https://frontendmasters.com/courses/api-node-rest-graphql/" rel="noopener">REST &amp; GraphQL API Design in Node.js, v2 (using Express &amp; MongoDB)</a></li></ul><p>Durante esse tempo, eu também estava me voluntariando para a "1MWTT" e me pediram para construir uma aplicação de <a href="https://probot.github.io/docs/">Probot</a> para a integração de voluntários com o Node. Isso também me deu um pouco de prática com o Node, o que foi muito divertido.</p><p><strong><strong>QA </strong>e segurança da informação<strong>: </strong></strong>este módulo também ajudou a abrir meus olhos. Até então, eu nunca tinha escrito um único teste na minha vida. Agora, eu adoro escrever testes e até fiquei muito interessada em Test Driven Development.</p><p>Eu usei, principalmente, as documentações para essa seção, mas então decidi testar meu front-end também, e encontrei este curso incrível na Udemy que não posso recomendar o suficiente. A instrutora é de longe a melhor instrutora que já vi na Udemy. Mal posso esperar para consumir quaisquer outros cursos que ela lance no futuro.</p><p>- <a href="https://www.chaijs.com/api/bdd/" rel="noopener">Documentação do Chai</a></p><p>- <a href="https://www.udemy.com/react-testing-with-jest-and-enzyme/" rel="noopener">React Testing with Jest and Enzyme</a></p><p><strong><strong>Visualiza</strong>ção de dados com o<strong> D3:</strong></strong> este foi o certificado mais difícil, com certeza. As explicações foram boas, mas uma vez que você chega aos projetos, descobre que os desafios cobrem apenas o primeiro projeto, e você está meio sozinho para o resto. Não há muitos bons recursos on-line. Li principalmente as documentações e usei tutoriais. Aqui estão os recursos que finalmente me fizeram passar por essa certificação:</p><p> <a href="https://www.youtube.com/watch?v=n5NcCoa9dDU&amp;list=PL6il2r9i3BqH9PmbOf5wA5E1wOG3FT22p" rel="noopener">DTutoriais de D3.js, por d3Vienno</a></p><p>- <a href="https://github.com/d3/d3/wiki" rel="noopener">Documentação do D3</a></p><h4 id="dicas-para-terminar-o-curr-culo"><strong><strong>Dicas para terminar o currículo</strong></strong></h4><p>Resumindo, essas são as coisas que mais me ajudaram a cumprir meu objetivo de terminar o currículo:</p><ul><li>Use o currículo como um roteiro, mas complemente com outros recursos</li><li>Não fique preso por muito tempo: faça perguntas, consulte o Google, programe com seus pares.</li><li>Estabeleça metas realistas para cada dia e semana. Não sofra se em uma semana você estiver mais lenta: a vida acontece. Não deixe que isso tire você do rumo.</li><li>Tenha sua motivação em mente: é o que vai garantir que você siga, mesmo nos dias difíceis.</li><li>Priorize: você terá que reduzir o tempo que gasta fazendo outras coisas.</li><li>Não se esqueça de tirar dias de folga. Eles são vitais para o processo de aprendizagem. Não se esqueça, também, de dormir o suficiente!</li></ul><p>Depois do freeCodeCamp, me senti um pouco perdida. Esse foi o roteiro que me guiou através da minha jornada de professora a desenvolvedora.</p><p>Depois de alguns dias de reflexão e planejamento, me dediquei ao meu projeto paralelo que estou construindo com meu marido. Estamos aprendendo e nos divertindo e estamos muito animados com isso.</p><p><strong>Sim, eu recebi uma oferta de emprego logo após terminar o currículo</strong>, mas falarei mais sobre isso em um próximo artigo.</p><p>Em resumo, eu não poderia ter aprendido tudo o que aprendi tão rapidamente se não fosse pelo freeCodeCamp e sou extremamente grata a todos que tornam possível um projeto tão maravilhoso.</p><p>Se você sente o mesmo e é capaz de retribuir, considere fazer uma doação para o freeCodeCamp <a href="https://www.freecodecamp.org/donate/">aqui</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Usando a busca em largura para encontrar os caminhos mínimos ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Sachin Malhotra Você sabe qual foi o volume global de tráfego aéreo em 2017? Sabe qual foi o aumento do tráfego aéreo nos últimos anos? Bem, vamos dar uma olhada em alguns dados. Fonte:  https://www.statista.com/statistics/564769/airline-industry-number-of-flights/De acordo com a Organização da Aviação Civil Internacional [https://www.icao.int/Pages/default.aspx] (ICAO), um recorde ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/usando-a-busca-em-largura-para-encontrar-os-caminhos-minimos/</link>
                <guid isPermaLink="false">6501e3ebc4bdc9102ef6fa3f</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Luis felipe L. C. ]]>
                </dc:creator>
                <pubDate>Thu, 11 Apr 2024 08:13:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/1_Dn4pxbJWrya6g1h0NNhaHw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/exploring-the-applications-and-limits-of-breadth-first-search-to-the-shortest-paths-in-a-weighted-1e7b28b3307/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Finding Shortest Paths using Breadth First Search</a>
      </p><p>Escrito por: Sachin Malhotra</p><p>Você sabe qual foi o volume global de tráfego aéreo em 2017? Sabe qual foi o aumento do tráfego aéreo nos últimos anos? Bem, vamos dar uma olhada em alguns dados.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/6eQAOZ4fqSw7oBxo8eAFormyD7h6woe8upoG.png" class="kg-image" alt="6eQAOZ4fqSw7oBxo8eAFormyD7h6woe8upoG" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/03/6eQAOZ4fqSw7oBxo8eAFormyD7h6woe8upoG.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/03/6eQAOZ4fqSw7oBxo8eAFormyD7h6woe8upoG.png 800w" sizes="(min-width: 720px) 720px" width="800" height="528" loading="lazy"><figcaption>Fonte: <a href="https://www.statista.com/statistics/564769/airline-industry-number-of-flights/">https://www.statista.com/statistics/564769/airline-industry-number-of-flights/</a></figcaption></figure><p>De acordo com a <a href="https://www.icao.int/Pages/default.aspx">Organização da Aviação Civil Internacional</a> (ICAO), um recorde de 4,1 bilhões de passageiros foram transportados pelo setor de aviação em 2017. Além disso, o número de voos no mundo subiu para 37 milhões em 2017.</p><p>São muitos passageiros, e muitos voos ocupando o espaço aéreo diariamente no mundo inteiro. Como existem centenas de milhares desses voos, é provável que existam rotas diferentes que tenham mais de uma parada entre um lugar e outro.</p><p>Cada voo tem sua própria origem e destino, bem como um preço padrão de assento de classe econômica associado a ele. Vamos deixar de lado as passagens sofisticadas da classe executiva, o espaço adicional para as pernas e tudo mais!</p><p>Nesse cenário, é muito confuso escolher qual voo seria o melhor se quiséssemos ir de um lugar para outro.</p><p>Vamos ver o número de opções de voos que o <a href="https://www.studentuniverse.com/?noMoreRedirect=true">StudentUniverse</a> (oferece descontos para estudantes 😜) me proporciona, partindo de Los Angeles a Nova Délhi.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/X9oBIPVUCIw5YKvkkmc8TymNyLLWtZdKto31.png" class="kg-image" alt="X9oBIPVUCIw5YKvkkmc8TymNyLLWtZdKto31" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/03/X9oBIPVUCIw5YKvkkmc8TymNyLLWtZdKto31.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/03/X9oBIPVUCIw5YKvkkmc8TymNyLLWtZdKto31.png 644w" width="644" height="110" loading="lazy"><figcaption>Cada voo tem um link Details, então pesquisamos e encontramos um total de 119 voos</figcaption></figure><p>Estão sendo oferecidos 119 voos no total. Em seguida, aparece um <em>pop-up</em> no site informando que há outros sites que podem estar oferecendo voos semelhantes com tarifas ainda mais baratas. 😩</p><p>Uma variedade de sites e incontáveis voos – e estamos falando apenas de uma origem e destino.</p><p>Como desenvolvedor, se eu quisesse resolver esse problema, criaria um sistema para atender com eficiência às seguintes consultas:</p><ul><li>Número total de destinos acessíveis (com um número máximo de paradas) a partir da minha localização atual, listando também esses destinos.<br>É preciso manter as opções em aberto quando se deseja viajar 😃.</li><li>É um fato conhecido (minha opinião 😉) que rotas com escalas tendem a ser mais baratas que voos diretos.<br>Assim, dada uma origem e um destino, podemos querer encontrar rotas com pelo menos 2 ou 3 paradas.</li><li>Mais importante: qual é a rota mais barata, dada uma origem e destino?</li><li>E.... bem, vamos deixar isso pro final 🙈.</li></ul><p>Como você pode imaginar, existiriam potencialmente milhares de voos como resultado das duas primeiras consultas. Certamente, porém, podemos reduzir isso fornecendo alguns outros critérios para diminuir o tamanho do resultado. Para o escopo deste artigo, vamos nos concentrar nesses tipos de consultas.</p><h3 id="modelando-a-rede-a-rea-como-um-grafo"><strong>Modelando a rede aérea como um grafo</strong></h3><p>O título deste artigo deixa bem claro que os grafos estariam envolvidos em algum lugar, não é mesmo?</p><p>Modelar esse problema como um problema de travessia de grafo simplifica bastante, tornando-o muito mais fácil de ser tratado. Portanto, como primeira etapa, vamos definir nosso grafo.</p><p>Modelamos o tráfego aéreo como um grafo:</p><ul><li>direcionado</li><li>possivelmente cíclico</li><li>ponderado</li><li>de floresta. <strong><strong>G (V, E)</strong></strong></li></ul><p><strong><strong>Direc</strong>ionado</strong> porque cada voo terá uma origem e destino designados. Isso significa muita coisa.</p><p><strong><strong>C</strong>íclico </strong>porque há grande possibilidade de encontrar vários voos que partam de um determinado local e terminem no mesmo local.</p><p><strong>Ponderado </strong>porque cada voo tem um custo associado a ele – no caso, poderia ser o custo da passagem aérea da classe econômica citada no início deste artigo.</p><p>Por fim, é um grafo de <strong><strong>f</strong>loresta </strong>porque podemos ter múltiplos componentes conectados. Não é necessário que todas as cidades do mundo tenham algum tipo de rede aérea entre elas. Assim, o grafo pode ser desconectado e, portanto, uma floresta.</p><p>Os vértices, <strong><strong>V</strong></strong>, seriam os locais em todo o mundo onde há aeroportos em funcionamento.</p><p>As arestas, <strong><strong>E</strong> </strong>(do inglês, <em>edges</em>), representariam todos os voos que constituem o tráfego aéreo. Uma aresta <code>u --&gt; v</code> simplesmente significa que você tem um voo direcionado da localização/nó u até v .</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/fUMFpsXMA9AJOyZjsIVzphouaIrojTB3nPbq.png" class="kg-image" alt="fUMFpsXMA9AJOyZjsIVzphouaIrojTB3nPbq" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/03/fUMFpsXMA9AJOyZjsIVzphouaIrojTB3nPbq.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/03/fUMFpsXMA9AJOyZjsIVzphouaIrojTB3nPbq.png 800w" sizes="(min-width: 720px) 720px" width="800" height="1305" loading="lazy"><figcaption>Exemplo de rede aérea com os respectivos custos para diferentes voos.</figcaption></figure><p>Agora que temos uma ideia de como modelar a rede aérea em um grafo, vamos prosseguir e resolver a primeira consulta básica que um usuário pode ter.</p><h3 id="n-mero-total-de-destinos-acess-veis"><strong>Número total de destinos acessíveis</strong></h3><p>Quem não gosta de viajar?</p><p>Como alguém que gosta de explorar lugares diferentes, seria interessante saber quais destinos são acessíveis a partir de seu aeroporto local. Novamente, haveria critérios adicionais aqui para reduzir os resultados dessa consulta. Para fins didáticos, vamos apenas encontrar todos os locais acessíveis a partir de nosso aeroporto local.</p><p>Agora que temos um grafo bem definido, podemos aplicar algoritmos de travessia para o computar.</p><p>A partir de um determinado ponto, podemos usar a <a href="https://pt.wikipedia.org/wiki/Busca_em_largura">busca em largura</a> (BFS, do inglês, <em>Breadth-First Search</em>) ou a <a href="https://pt.wikipedia.org/wiki/Busca_em_profundidade">busca em profundidade </a>(DFS, do inglês, <em>Depth-First Search</em>) para examinar o grafo ou os locais acessíveis a partir da localização inicial <strong>que tenham um número máximo de paradas<strong>.</strong></strong> Como este artigo trata exclusivamente do algoritmo de busca em largura, vamos ver como podemos usar o famoso BFS para realizar essa tarefa.</p><p>Vamos inicializar a fila do BFS com o local fornecido como o ponto de partida. Em seguida, executamos o primeiro percurso em largura e continuamos até que a fila esteja vazia ou até que o número máximo de paradas tenha se esgotado.</p><p><strong>Observação<strong>: </strong></strong>se você não estiver familiarizado com a busca em largura ou com a em profundidade, recomendo que leia este <a href="https://www.freecodecamp.org/news/deep-dive-into-graph-traversals-227a90c6a261">artigo</a> (texto em inglês) antes de continuar.</p><p>Vamos dar uma olhada no código que inicializa a nossa estrutura de dados do grafo. Também precisamos analisar como o algoritmo do BFS acabaria nos fornecendo todos os destinos acessíveis a partir de uma determinada origem.</p><pre><code>from collections import defaultdict
from pprint import pprint 
class FlightNetwork:
	def __init__(self):
		self.neighbors = defaultdict(list)
		self.cost = defaultdict(list)
		
	def add_flight(self, source, destination, price):
		self.neighbors[source].append(destination)
		self.cost[source].append(price)
	
	def show_flights(self):
		print("Destinos:");pprint(dict(self.neighbors))
		print("Custo:");pprint(dict(self.cost))
        
f = FlightNetwork()
f.add_flight('Los Angeles', 'New Delhi', 200)
f.add_flight('Los Angeles', 'Japan', 87)
f.add_flight('Germany', 'New Delhi', 125)
f.add_flight('Italy', 'Los Angeles', 150)
f.add_flight('New Delhi', 'France', 100)
f.add_flight('Los Angeles', 'France', 200)
f.add_flight('Italy', 'New Delhi', 300)
f.add_flight('France', 'Norway', 175)
f.add_flight('Ireland', 'Chicago', 100)
f.add_flight('Chicago', 'Italy', 135)
f.add_flight('Los Angeles', 'Ireland', 100)
f.add_flight('Ireland', 'New Delhi', 200)
f.show_flights()
Destinos:
{	
	'Chicago': ['Italy'],
 	'France': ['Norway'],
	'Germany': ['New Delhi'],
 	'Ireland': ['Chicago', 'New Delhi'],
 	'Italy': ['Los Angeles', 'New Delhi'],
 	'Los Angeles': ['New Delhi', 'Japan', 'France', 'Ireland'],
 	'New Delhi': ['France']
 }
Custo:
{
	'Chicago': [135],
 	'France': [175],
 	'Germany': [125],
 	'Ireland': [100, 200],
 	'Italy': [150, 300],
 	'Los Angeles': [200, 87, 200, 100],
 	'New Delhi': [100]
 }</code></pre><p>Agora que temos uma boa ideia de como o grafo deve ser inicializado, vamos dar uma olhada no código do algoritmo do BFS.</p><p>Executando o <code>bfs</code> na cidade de Los Angeles, o resultado seriam os seguintes destinos acessíveis:</p><pre><code>{'Chicago', 'France', 'Ireland', 'Italy', 'Japan', 'New Delhi', 'Norway'}</code></pre><p>Isso foi simples, não?</p><p>Veremos como podemos limitar o BFS a um número máximo de paradas mais adiante neste artigo.</p><p>Se tivéssemos uma rede aérea enorme, que é o que teríamos em um cenário de produção, então não desejaríamos necessariamente saber todos os destinos possíveis de um determinado ponto de partida.</p><p>Esse é um caso de uso quando a rede aérea for muito pequena ou pertencer apenas a poucas regiões dos Estados Unidos.</p><p>Porém, para uma rede grande, um caso de uso mais realista seria encontrar todas as rotas de voo que possuem várias paradas. Vamos examinar esse problema mais a fundo e ver como podemos resolvê-lo.</p><h3 id="rotas-com-m-ltiplas-paradas"><strong>Rotas com múltiplas paradas</strong></h3><p>É um fato bastante conhecido que, normalmente, para uma determinada origem e destino, uma viagem com múltiplas paradas é mais barata que um voo direto, sem escalas.</p><p>Muitas vezes, preferimos o voo direto para evitar as escalas, em especial porque os voos com várias paradas tendem a tomar muito tempo – o que não temos.</p><p>No entanto, se você não tiver nenhum compromisso urgente e quiser economizar algum dinheiro (e se sentir confortável com o voo que tem escalas – opção oferecida por diversas companhias aéreas) poderá, na verdade, se beneficiar muito ao fazer essa escolha.</p><p>Você pode passar por alguns dos lugares mais bonitos do mundo com seus modernos aeroportos. Isso já pode ser motivação o suficiente.</p><p>Em termos do modelo de grafo sobre o qual estávamos falando, dada uma origem e um destino, precisamos criar rotas com 2 ou mais paradas para uma origem e destino fornecidos.</p><p>Para um usuário final, pode ser que a resposta abaixo não seja a melhor:</p><pre><code>[A, C, D, B], 2 paradas, $X
[A, E, D, C, F, W, G, T, B], 8 paradas, $M
[A, R, E, G, B], 3 paradas, $K
[A, Z, X, C, V, B, N, S, D, F, G, H, B, 11 paradas, $P</code></pre><p>Eu sei. Ninguém em sã consciência escolheria um voo com 11 paradas, mas o que estou tentando dizer é que um usuário final espera simetria. Ou seja, ele desejaria ver primeiro todos os voos com 2 paradas, depois todos os voos com 3 e assim por diante até um máximo de, digamos, 5 paradas.</p><p>Porém, todas as rotas de voo com o mesmo número de paradas entre elas devem ser exibidas juntas. Esse é um requisito necessário.</p><p>Então, vamos ver como podemos resolver isso. Dado um grafo de redes aéreas, um ponto de partida <code>S</code> (do inglês, <em>source</em>) e um destino <code>D</code>, precisamos realizar um percurso em nível e guardar as rotas de voo de <code>S --&gt; D</code> com pelo menos 2 e no máximo 5 paradas entre elas. Isso quer dizer que precisamos realizar um percurso em nível até uma profundidade de 7 partindo do nó inicial <code>S</code>.</p><p>Aqui está o código para resolver esse problema:</p><pre><code>
{'A': ['C', 'B', 'F'],
 'B': ['D'],
 'C': ['B', 'M', 'E', 'F'],
 'D': ['C', 'E', 'F'],
 'E': ['F'],
 'M': ['F']}
Custo:
{'A': [10, 20, 14],
 'B': [20],
 'C': [120, 200, 145, 50],
 'D': [75, 45, 60],
 'E': [60],
 'M': [45]}
parent = f.level_order_traversal('A', 'F', (2,5))
for r in range(2, 6):
    print("\nOs voos com {} paradas no meio são os seguintes:".format(r))
    routes = f.get_route(('F', r), 'A', parent)
    for r in routes:
        print(r)
Os voos com 2 paradas no meio são os seguintes:
A--&gt;C--&gt;M--&gt;F
A--&gt;C--&gt;E--&gt;F
A--&gt;B--&gt;D--&gt;F

Os voos com 3 paradas no meio são os seguintes:
A--&gt;C--&gt;B--&gt;D--&gt;F
A--&gt;B--&gt;D--&gt;C--&gt;F
A--&gt;B--&gt;D--&gt;E--&gt;F

Os voos com 4 paradas no meio são os seguintes:
A--&gt;C--&gt;B--&gt;D--&gt;C--&gt;F
A--&gt;C--&gt;B--&gt;D--&gt;E--&gt;F
A--&gt;B--&gt;D--&gt;C--&gt;E--&gt;F
A--&gt;B--&gt;D--&gt;C--&gt;M--&gt;F
A--&gt;C--&gt;B--&gt;D--&gt;E--&gt;F
A--&gt;B--&gt;D--&gt;C--&gt;E--&gt;F

Os voos com 5 paradas no meio são os seguintes:
A--&gt;C--&gt;B--&gt;D--&gt;C--&gt;M--&gt;F
A--&gt;C--&gt;B--&gt;D--&gt;C--&gt;E--&gt;F
A--&gt;B--&gt;D--&gt;C--&gt;B--&gt;D--&gt;F</code></pre><p>Essa pode não ser a melhor maneira de resolver esse problema quando ele for muito grande – uma grande restrição de memória aconteceria por conta dos nós presentes na fila no momento.</p><p>Como cada nó, ou localização, pode ter milhares de voos para diferentes destinos do mundo, a fila poderia se tornar enorme se fôssemos armazenar dados reais de voos dessa maneira. Esse exemplo é apenas para demonstrar um dos casos de uso do algoritmo de busca em largura.</p><p>Por agora, vamos nos concentrar apenas no percurso e ver o que acontece na prática. O algoritmo de percurso é simples, porém, toda a complexidade espacial do percurso em nível se dá graças a elementos presentes na fila e de seu tamanho.</p><p>Existem muitas formas de se implementar esse algoritmo. Além disso, cada uma delas varia em termos de consumo máximo memória em determinado momento pelos elementos presentes na fila.</p><p>Queremos saber o consumo máximo de memória da fila em um dado momento durante o percurso em nível. Antes disso, vamos construir uma rede aérea aleatória com preços aleatórios.</p><pre><code>from collections import defaultdict
import random
from pprint import pprint

def add_edge(s, d, adj_list):
    adj_list[s].append(d)

nodes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']  
adj_list = defaultdict(list)
for i, s in enumerate(nodes[:5]):
    for i in range(10 - i):
        while True:
            d = (nodes[random.randint(0, 8)], "$"+str(random.randint(50, 500)))
            if d[0] != s:
                break
        add_edge(s, d, adj_list)</code></pre><p>Agora a implementação do percurso em nível.</p><pre><code>import sys
def level_order_naive(source, max_level):
    queue = [(source, 0)]
    max_memory = 0
    levels = []
    while queue:
        max_memory = max(max_memory, sum(list(map(sys.getsizeof, queue))))
        element, level = queue.pop(0)
        levels.append((element, level))
        if level == max_level:
            continue
        if element in adj_list:
            for neighbor in adj_list[element]:
                queue.append((neighbor[0], level + 1))
                
    return max_memory, levels  </code></pre><p>Essa, por sinal, é a implementação mais simples e direta do algoritmo de percurso em nível.</p><p>Junto a cada nó que adicionamos à fila, armazenamos também as informações de nível e uma tupla de <code>(nó, nível)</code> dentro da fila. Assim, toda a vez que removermos um elemento da fila, teremos as informações do nível em que estava.</p><p>As informações de nível, para nosso caso de uso, são o número de paradas desde a origem até esse local específico em nossa rota de voo.</p><p>A questão é que podemos fazer otimizações, já que consumo de memória no programa precisa ser levado em consideração. Aqui está uma abordagem um pouco melhorada de como se fazer o percurso em nível.</p><pre><code>def level_order_NULL(source, max_level):
    queue = [source, None]
    max_memory = 0
    level = 0
    levels = []
    while queue:
        max_memory = max(max_memory, sum(list(map(sys.getsizeof, queue))))
        element = queue.pop(0)
        if element:
            levels.append((element, level))
        if level == max_level:
            continue
        if not element:
            level += 1
            queue.append(None)
            continue
            
        if element in adj_list:
            for neighbor in adj_list[element]:
                queue.append(neighbor[0])
                
    return max_memory, levels </code></pre><p>A ideia aqui é que não vamos armazenar nenhuma informação extra aos nós que estão sendo adicionados na fila. Usamos um objeto <code>None</code> para marcar o fim do nível. Não sabemos o tamanho de nenhum nível de antemão a não ser o do primeiro nível, que tem apenas o nosso nó <code>source</code>.</p><p>Assim, iniciamos a fila com <code>[source, None]</code> e continuamos a remover elementos. Toda vez que encontramos um elemento <code>None</code>, saberemos que o nível terminou e que o seguinte começou. Adicionamos outro <code>None</code> para marcar o final desse novo nível.</p><p>Considere o simples grafo abaixo. Vamos ver rapidamente como isso funcionaria na prática.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/goYMjFvXtEMQAndVXKeUTy2gPOrYPARq1H3k.png" class="kg-image" alt="goYMjFvXtEMQAndVXKeUTy2gPOrYPARq1H3k" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/03/goYMjFvXtEMQAndVXKeUTy2gPOrYPARq1H3k.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/03/goYMjFvXtEMQAndVXKeUTy2gPOrYPARq1H3k.png 800w" sizes="(min-width: 720px) 720px" width="800" height="867" loading="lazy"></figure><pre><code>**************************************************** LEVEL 0 begins
level = 0, queue = [A, None]
level = 0, pop, A, push, B, C, queue = [None, B, C]
pop None ******************************************* LEVEL 1 begins
push None
level = 1, queue = [B, C, None]level = 1, pop, B, push, C, D, F, queue = [C, None, C, D, F]
level = 1, pop, C, push, D, D (lol!), queue = [None, C, D, F, D, D]
pop None ******************************************* LEVEL 2 begins
push None
level = 2, queue = [C, D, F, D, D, None] .... e assim por diante</code></pre><p>Espero que a explicação tenha esclarecido o funcionamento do algoritmo. Esse certamente é um método interessante de se fazer o percurso em nível, monitorar níveis e não se preocupar muito com o uso de memória. Sem dúvida, reduz o volume de memória usado pelo código.</p><p>Porém, não fique muito entusiasmado pensando que isso foi uma melhoria significativa.</p><p>Quero dizer, é significativa, mas você deveria estar se fazendo duas perguntas:</p><ol><li>De que tamanho foi essa melhoria?</li><li>Podemos melhorar ainda mais?</li></ol><p>Vou responder as duas e começarei pela segunda. A resposta é Sim!</p><p>Podemos fazer uma melhoria aqui ao eliminar completamente a necessidade do <code>None</code> dentro da fila. A motivação para essa abordagem vem da própria abordagem anterior.</p><p>Se você observar atentamente o algoritmo acima, perceberá que toda vez que retiramos um <code>None</code>, um nível é concluído e outro está pronto para ser processado. O importante é que exista um nível seguinte inteiro dentro da fila no momento em que ocorre a remoção do <code>None</code>. Podemos utilizar essa ideia de considerar o tamanho da fila na lógica do percurso.</p><p>Aqui está o pseudocódigo desse algoritmo otimizado:</p><pre><code>queue = Queue()
queue.push(S)
level = 0
while queue is not empty {
	size = queue.size()
    // size representa o número de elementos no nível atual
    for i in 1..size {
    	element = queue.pop()
        // Processe o elemento aqui
        // Realize uma série de operações queue.push() aqui
    level += 1</code></pre><p>Aqui está o código dele.</p><pre><code>def level_order_queue_size(source, max_level):
    queue = [source]
    max_memory = 0
    levels = []
    level = 0
    while queue:
        max_memory = max(max_memory, sum(list(map(sys.getsizeof, queue))))
        size = len(queue)
        for _ in range(size):
            element = queue.pop(0)
            levels.append((element, level))
            if level == max_level:
                continue
            if element in adj_list:
                for neighbor in adj_list[element]:
                    queue.append(neighbor[0])
        level += 1            
                
    return max_memory, levels  </code></pre><p>O pseudocódigo é autoexplicativo. Basicamente, eliminamos a necessidade de um elemento <code>None</code> por nível e, ao invés disso, usamos o tamanho da fila para mudar de nível. Isso também leva a uma melhoria em relação ao último método, mas em que proporção?</p><p>Dê uma olhada no Jupyter Notebook a seguir para ver a diferença de consumo de memória entre os três métodos.</p><pre><code>from collections import defaultdict
import random
from pprint import pprint

def add_edge(s, d, adj_list):
    adj_list[s].append(d)

nodes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']  
adj_list = defaultdict(list)
for i, s in enumerate(nodes[:5]):
    for i in range(10 - i):
        while True:
            d = (nodes[random.randint(0, 8)], "$"+str(random.randint(50, 500)))
            if d[0] != s:
                break
        add_edge(s, d, adj_list)
adj_list['A']
[('G', '$418'), ('F', '$75'), ('H', '$141'), ('D', '$203'), ('D', '$101'), ('I', '$51'), ('G', '$187'), ('H', '$137'), ('F', '$425'), ('F', '$69')]
import sys
def level_order_naive(source, max_level):
    queue = [(source, 0)]
    max_memory = 0
    levels = []
    while queue:
        max_memory = max(max_memory, sum(list(map(sys.getsizeof, queue))))
        element, level = queue.pop(0)
        levels.append((element, level))
        if level == max_level:
            continue
        if element in adj_list:
            for neighbor in adj_list[element]:
                queue.append((neighbor[0], level + 1))
                
    return max_memory, levels                
max_memory, levels = level_order_naive('A', 5)
max_memory, levels[50:60],len(levels)
(20224, [('H', 3), ('I', 3), ('D', 3), ('B', 3), ('B', 3), ('A', 3), ('B', 3), ('F', 3), ('I', 3), ('G', 3)], 523)
def level_order_NULL(source, max_level):
    queue = [source, None]
    max_memory = 0
    level = 0
    levels = []
    while queue:
        max_memory = max(max_memory, sum(list(map(sys.getsizeof, queue))))
        element = queue.pop(0)
        if element:
            levels.append((element, level))
        if level == max_level:
            continue
        if not element:
            level += 1
            queue.append(None)
            continue
            
        if element in adj_list:
            for neighbor in adj_list[element]:
                queue.append(neighbor[0])
                
    return max_memory, levels 
max_memory, levels = level_order_NULL('A', 5)
max_memory, levels[50:60], len(levels)
(15816, [('H', 3), ('I', 3), ('D', 3), ('B', 3), ('B', 3), ('A', 3), ('B', 3), ('F', 3), ('I', 3), ('G', 3)], 523)
def level_order_queue_size(source, max_level):
    queue = [source]
    max_memory = 0
    levels = []
    level = 0
    while queue:
        max_memory = max(max_memory, sum(list(map(sys.getsizeof, queue))))
        size = len(queue)
        for _ in range(size):
            element = queue.pop(0)
            levels.append((element, level))
            if level == max_level:
                continue
            if element in adj_list:
                for neighbor in adj_list[element]:
                    queue.append(neighbor[0])
        level += 1            
                
    return max_memory, levels              
max_memory, levels = level_order_queue_size('A', 5)
max_memory, levels[50:60], len(levels)
(15800, [('H', 3), ('I', 3), ('D', 3), ('B', 3), ('B', 3), ('A', 3), ('B', 3), ('F', 3), ('I', 3), ('G', 3)], 523)
sys.getsizeof(('A', 4))
64
sys.getsizeof(None)
16</code></pre><ul><li>Monitoramos o tamanho máximo da fila a qualquer momento quando consideramos a soma dos tamanhos de cada elemento contido na fila.</li><li>De acordo com a documentação do Python, <code>sys.getsizeof</code> retorna o ponteiro do objeto, ou tamanho, da referência em bytes. Assim, economizamos praticamente 4.4Kb de espaço <code>(20224 — 15800 bytes)</code> quando alteramos o algoritmo original do percurso em nível para usar <code>None</code>. Esta é apenas a economia de memória desse exemplo aleatório que usamos, e descemos apenas até o 5° nível do percurso.</li><li>O último método economiza apenas 16 bytes em relação ao método com <code>None</code>. Isso acontece porque apenas eliminamos os 4 objetos <code>None</code> que estavam sendo usados para marcar os 4 níveis (com exceção do primeiro) que foram processados. Cada ponteiro (ponteiro para um objeto) tem um tamanho de 4 bytes no Python rodando em um ambiente de 32 bits.</li></ul><p>Agora que temos todas essas rotas interessantes de múltiplos caminhos, partindo de nossa origem a nosso destino, e algoritmos de percurso em nível altamente eficientes para resolver esse problema, podemos analisar um problema mais lucrativo para resolver usando nosso BFS.</p><p>Qual é a rota de voo mais barata, partindo da minha origem até um determinado destino? Eis ai algo capaz de despertar o interesse de todos imediatamente. Quero dizer, quem não quer economizar dinheiro?</p><h3 id="caminho-m-nimo-de-uma-determinada-origem-a-um-destino"><strong>Caminho mínimo de uma determinada origem a um destino</strong></h3><p>Não há muita descrição a ser dada para o enunciado do problema. Precisamos apenas encontrar o caminho mínimo e deixar o usuário final satisfeito.</p><p>Algoritmicamente, dado um grafo direcionado ponderado, precisamos encontrar o caminho mínimo da origem ao destino. O mais curto ou o mais barato seriam a mesma coisa do ponto de vista do algoritmo.</p><p>Não vamos descrever uma possível solução BFS para esse problema porque por ela o problema é intratável. Vejamos o grafo abaixo para entender por que esse é o caso.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/ISBXi5XsxIfQ5AhgHeKmsEwBw12x8GtAsZRM.png" class="kg-image" alt="ISBXi5XsxIfQ5AhgHeKmsEwBw12x8GtAsZRM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/03/ISBXi5XsxIfQ5AhgHeKmsEwBw12x8GtAsZRM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/03/ISBXi5XsxIfQ5AhgHeKmsEwBw12x8GtAsZRM.png 800w" sizes="(min-width: 720px) 720px" width="800" height="1179" loading="lazy"></figure><p>Dizemos que o BFS é o algoritmo a ser usado se quisermos encontrar o caminho mínimo em um grafo <a href="https://www.freecodecamp.org/news/deep-dive-into-graph-traversals-227a90c6a261">não direcionado e não ponderado</a> (texto em inglês). O princípio do BFS é que, na primeira vez que um nó é descoberto durante o percurso, a distância entre ele e o ponto de partida se torna o caminho mínimo.</p><p>O mesmo não pode ser dito de um grafo ponderado. Considere o grafo acima. Se, por exemplo, tivéssemos que encontrar o caminho mínimo do nó <code>A</code> ao <code>B</code> numa versão não direcionada desse grafo, então o caminho mínimo seria a aresta que liga A a B. Assim, o caminho mínimo teria tamanho <code>1</code> e o BFS funcionaria com precisão.</p><p>Entretanto, estamos lidando com um grafo ponderado. Logo, a primeira descoberta de um nó durante o percurso <strong>não garante</strong> o caminho mínimo para esse nó. Por exemplo, no diagrama acima, o nó <code>B</code> seria descoberto logo no início porque é vizinho de <code>A</code> e o custo associado a esse caminho (uma aresta, nesse caso) seria <code>25</code> . Porém, esse não é o caminho mínimo. O caminho mínimo é <code>A --&gt; M --&gt; E --&gt; B</code> , que tem tamanho 10.</p><p>A busca em largura não tem como saber se a descoberta de um nó em particular vai nos fornecer o caminho mínimo para esse nó. Portanto, a única maneira possível de o BFS (ou DFS) encontrar o caminho mínimo em um grafo ponderado é varrendo o grafo inteiro e ir registrando a distância mínima da origem até o vértice destino.</p><p>Essa solução não é viável para uma rede enorme como a nossa rede aérea, que provavelmente teria milhares de nós.</p><p>Não entraremos em detalhes sobre como podemos lidar com isso. Está fora do escopo deste artigo.</p><p>O que você faria se eu dissesse que o BFS é o algoritmo certo para encontrar o caminho mínimo em um grafo ponderado <strong>sob uma pequena condição?</strong></p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/a5viI92PAF89q" width="480" height="331" frameborder="0" class="giphy-embed" allowfullscreen="" title="Conteúdo incorporado" loading="lazy"></iframe><p><a href="https://giphy.com/gifs/reaction-a5viI92PAF89q">via GIPHY</a></p><!--kg-card-end: html--><h3 id="caminhos-m-nimos-com-restri-es"><strong>Caminhos mínimos com restrições</strong></h3><p>Como o grafo que teríamos para a rede aérea é enorme, sabemos que explorá-lo completamente não é uma possibilidade plausível.</p><p>Considere o problema dos caminhos mínimos a partir da perspectiva de um cliente. Quando ele quer reservar um voo, estas são as opções que ele idealmente considera:</p><ul><li>O voo não deve ser muito longo</li><li>Deve caber no orçamento (muito importante)</li><li>Pode ter algumas paradas, mas não mais do que <code>K</code>, onde <code>K</code> pode variar dependendo do cliente.</li><li>Por fim, temos as preferências pessoais que envolvem coisas como acesso a <em>lounges</em>, qualidade da comida, locais de escala e espaço médio para as pernas.</li></ul><p>O ponto principal a ser considerado aqui é o terceiro: pode ter algumas paradas, mas não mais do que <code>K</code>, onde <code>K</code> pode variar dependendo do cliente.</p><p>O cliente quer a rota de voo mais barata, mas também não quer, digamos, 20 paradas entre seu ponto de partida e seu destino. O cliente pode concordar com um máximo de 3 paradas ou, em casos extremos, talvez até 4, mas não mais do que isso.</p><p>Gostaríamos de ter um programa que descobrisse a rota de voo mais barata com <a href="https://leetcode.com/problems/cheapest-flights-within-k-stops/description/">no máximo K paradas</a> para uma determinada origem e destino.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/A3qPvKhi2p6Rfed4e28pAsR5wFDaB31-ai5V.png" class="kg-image" alt="A3qPvKhi2p6Rfed4e28pAsR5wFDaB31-ai5V" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/03/A3qPvKhi2p6Rfed4e28pAsR5wFDaB31-ai5V.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/03/A3qPvKhi2p6Rfed4e28pAsR5wFDaB31-ai5V.png 800w" sizes="(min-width: 720px) 720px" width="800" height="470" loading="lazy"><figcaption>Fonte: <a href="https://www.freecodecamp.org/portuguese/news/usando-a-busca-em-largura-para-encontrar-os-caminhos-minimos/Leetcode.com">Leetcode.com</a></figcaption></figure><p>Essa questão do LeetCode foi a principal motivação para que eu escrevesse este artigo. Recomendo fortemente que você analise a questão ao menos uma vez e não confie somente no print que está acima.</p><p>"Por que o BFS funcionaria aqui?", alguém poderia perguntar. "Esse também é um grafo ponderado e o motivo pelo qual o BFS não funciona nele. Assim como discutimos na seção anterior, o conceito deveria ser o mesmo." NÃO!</p><p>O número de níveis alcançados pela busca é limitado pelo valor de <code>K</code> em questão, descrição fornecida no início da seção. Portanto, essencialmente, estaríamos buscando o caminho mínimo, mas não precisaríamos varrer o grafo inteiro. Vamos apenas até o nível <code>K</code>.</p><p>Em um cenário real, o valor de <code>K</code> seria menor que 5 para qualquer passageiro mentalmente são 😝.</p><p>Vamos analisar o pseudocódigo do algoritmo:</p><pre><code>def bfs(source, destination, K):
      min_cost = dictionary representing min cost under K stops for each node reachable from source. 
      set min_cost of source to be 0
      Q = queue()
      Q.push(source)
      stops = 0
      while Q is not empty {
           size = Q.size
           for i in range 1..size {
                 element = Q.pop() 
                 if element == destination then continue
                 for neighbor in adjacency list of element {
                        if stops == K and neighbor != destination        then continue  
                        if min_cost of neighbor improves, update and add back to the queue.
                }
           }    
           stops ++ 
      }</code></pre><p>Novamente, trata-se de um percurso em nível, e a abordagem usada aqui é a que faz uso do tamanho da fila em todos os níveis. Vamos dar uma olhada em uma versão comentada do código para resolver esse problema.</p><pre><code>from collections import defaultdict
class Solution:
    def findCheapestPrice(self, n, flights, src, dst, K):
        """
        :type n: int
        :type flights: List[List[int]]
        :type src: int
        :type dst: int
        :type K: int
        :rtype: int
        """
        
        # Construa a estrutura de lista de adjacência para ser usada na travessia de ordem de nível. 
        adj_list = defaultdict(list)
        for s, d, cost in flights:
            adj_list[s].append((d, cost)) 
        
        # Inicie um dicionário com os valores de custo mínimo como +inf e 0 para o nó de origem. 
        min_cost = {k: float("inf") for k in range(n)}
        min_cost[src] = 0
        queue = [src]
        stops = 0
        
        # Execute o while enquanto a fila não estiver vazia, ou seja, enquanto não tivermos examinado todos os nós possíveis de acordo com as restrições. 
        while queue:
            size = len(queue)
            for _ in range(size):
                element = queue.pop(0)
                # Quando um elemento é removido da fila, seu custo atual será o custo mínimo até o momento, da origem até aquele elemento. 
                cost = min_cost[element]
                
                # Não é necessário processar os filhos do nó de destino. 
                if element == dst:
                    continue
                
                # Se esse nó tiver vizinhos
                if element in adj_list:
                    for neighbor, direct_flight_cost in adj_list[element]:
                           
                        # Não é necessário atualizar o custo mínimo se já esgotamos nossas K paradas.
                        if stops == K and neighbor != dst:
                            continue
                        
                        # Se o comprimento do caminho mínimo atual para `neighbor` puder melhorar, melhore e faça a nova fila
                        if  direct_flight_cost + cost &lt;  min_cost[neighbor]:
                            min_cost[neighbor] = direct_flight_cost + cost
                            queue.append(neighbor)
                            
            # Incremente o nível                
            stops += 1                
        return -1 if min_cost[dst] == float("inf") else  min_cost[dst]</code></pre><p><strong>Essencialmente, mantemos o controle da distância mínima de cada nó em relação a uma determinada origem. A distância mínima para a origem seria 0 e +inf para todos os outros inicialmente.</strong></p><p>Sempre que encontrarmos um nó, checamos se o comprimento mínimo do caminho em questão pode ser melhorado ou não. Se puder ser melhorado, isso significa que encontramos um caminho alternativo da origem até esse vértice que tem um custo menor - uma rota de voo mais barata até esse vértice. Colocamos esse vértice na fila novamente para que os locais e nós acessíveis a partir desse vértice também sejam atualizados (podendo ou não ser).</p><p>O ponto chave é esse:</p><pre><code># Não é necessário atualizar o custo mínimo se já esgotamos nossas K paradas. 
if stops == K and neighbor != dst:    continue</code></pre><p>Assim, retiramos o nó A representado por <code>element</code> no código e <code>neighbor</code> pode tanto ser um destino como outro nó qualquer. Se já tivermos esgotado nossas <code>K</code> paradas com o <code>element</code> sendo a K-ésima parada, então não devemos processar e atualizar (possivelmente) a distância mínima para o <code>neighbor</code>. Isso violaria nossa condição de <code>K</code> &nbsp;paradas nesse caso.</p><p>Como podem ver, resolvi esse problema originalmente usando programação dinâmica e levou cerca de 165ms para executar no site LeetCode. Executei usando BFS e foi megarrápido, levando apenas 45ms para executar. Essa foi motivação o suficiente para escrever este artigo para vocês.</p><p>Espero que tenham aproveitado este artigo sobre a busca em largura e algumas de suas aplicações. O foco principal foi mostrar sua aplicação ao problema do caminho mínimo em um grafo ponderado sob algumas condições😃.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Qual é a diferença entre escrever código e programar? ]]>
                </title>
                <description>
                    <![CDATA[ > Tradução em português europeu  Demorei algum tempo a compreender o que os termos programar e escrever código  realmente significam e o que cada campo implica. Tenho a certeza de que não sou o único que ficou confuso com estes termos quando estava a começar na área da ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/qual-e-a-diferenca-entre-escrever-codigo-e-programar/</link>
                <guid isPermaLink="false">64b00658b04bf0067ce23b1d</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Afonso Branco ]]>
                </dc:creator>
                <pubDate>Mon, 09 Oct 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/key-difference-between-coding-and-programming--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/difference-between-coding-and-programming/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">What is the Difference Between Coding and Programming?</a>
      </p><blockquote>Tradução em português europeu </blockquote><p>Demorei algum tempo a compreender o que os termos <strong><strong>program</strong>ar</strong> e <strong>escrever código</strong> realmente significam e o que cada campo implica. Tenho a certeza de que não sou o único que ficou confuso com estes termos quando estava a começar na área da tecnologia.</p><p>Durante algum tempo pensei que eram a mesma coisa e demorei algum tempo a perceber que existem diferenças entre os dois "mundos".</p><p>Neste artigo, vou explicar as diferenças básicas entre escrever código e programar, como cada um funciona e como trabalham em colaboração para desenvolver aplicações e sites.</p><p>Então, vamos explorar estes termos e como os profissionais os utilizam, começando por compreender o que eles significam.</p><h2 id="o-que-escrever-c-digo"><strong>O que é escrever código?</strong></h2><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/Untitled-design.png" class="kg-image" alt="Untitled-design" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/10/Untitled-design.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/10/Untitled-design.png 663w" width="663" height="398" loading="lazy"></figure><p>Podes ter visto cursos, bootcamps ou artigos a falar sobre escrever código – então porque enfatizamos este termo?</p><p>Isto acontece porque o simples ato de escrever código torna possível fazermos todas as coisas interessantes que fazemos todos os dias. Permite-nos utilizar aplicações <em>mobile</em>, trabalhar com programas diferentes e operar sistemas, e até mesmo brincar com os jogos que amamos, ou visitar o website onde estás a ler este artigo. É tudo possível através da escrita de código.</p><p>Então, o que é escrever código em termos simples?</p><p>Podemos definir a escrita de código como sendo o ato de traduzir instruções para um computador, de uma linguagem humana para uma linguagem que uma máquina consiga compreender. O código indica ao computador como se comportar e que ações deve realizar.</p><p>Se quiseres tornar-te um/a escritor/a de código, vais precisar de ter alguns conhecimentos básicos sobre linguagens de programação. Quando digo linguagens de programação, quero dizer linguagens como: Python, Java, Go, PHP ou JavaScript, só para mencionar algumas.</p><p>Abaixo está um bom exemplo de código escrito na linguagem Python, que irá converter qualquer <em><em>PDF</em></em> num <em><em>Audiobook</em></em>:</p><pre><code class="language-python">import PyPDF2                     # pip install pypdf
import pyttsx3                    # pip install pyttsx3
from tkinter.filedialog import *  # pip install tkinter

book = askopenfilename()
pdfReader = PyPDF2.PdfFileReader(book)

pages = pdfReader.numPages

for num in range(0, pages):
    page = pdfReader.getPage(num)
    text = page.extractText()
    speak = pyttsx3.init()
    speak.say(text)
    speak.runAndWait()
</code></pre><h2 id="o-que-programa-o"><strong>O que é programação?</strong></h2><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/fresh.png" class="kg-image" alt="fresh" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/10/fresh.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/10/fresh.png 663w" width="663" height="398" loading="lazy"></figure><p>Provavelmente, também já ouviste alguém a dizer, <em><em>"</em>Sou programador/a<em>"</em></em>. Algumas pessoas que utilizam este termo têm noção do significado do termo, enquanto outras pessoas não. Se não souberes exatamente o que significa programação, vamos tentar alcançar alguns esclarecimentos ao compreender o que realmente é programar.</p><p>Programar é o processo de criar as instruções que vão indicar ao computador como realizar uma tarefa em particular que lhe seja atribuída. Fazes isto ao utilizar linguagens de programação como:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/fresh--1-.png" class="kg-image" alt="fresh--1-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/10/fresh--1-.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/10/fresh--1-.png 663w" width="663" height="398" loading="lazy"></figure><p>Quando falamos de programação, pensa em algo como um controlo remoto da tua televisão – ele aguardará que tu lhe dês instruções ao pressionar diferentes botões, que por sua vez, indicam à televisão para realizar uma tarefa específica (como mudar de canal, aumentar o volume e assim adiante). Bem, é o mesmo modo com que os programadores podem instruir um computador a fazer várias coisas.</p><p>Com programação, podes fazer praticamente tudo – como programar robôs para ajudar nas lides domésticas, ou até mesmo programar carros autónomos como a Tesla.</p><p>De maneira a que um programador desenvolva um programa que implemente a sua ideia, é necessário realizar as seguintes tarefas:</p><ul><li>Planear a estrutura da aplicação (com a ajuda de ferramentas como o<em><em> Trello</em></em>)</li><li>Criar o design da aplicação (<em>ao utilizar ferramentas como<em> Figma o</em>u<em> Adobe</em>XD</em>)</li><li>Desenvolvê-la (<em>ao utilizar a sua linguagem de programação de eleição</em>)</li><li>Testar as suas funcionalidades</li><li>Implementá-la (<em>quer num serviço de alojamento gratuito quer pago</em>)</li><li>Fazer a manutenção depois de estar terminada.</li></ul><p>Por isso, como podes ver, podemos dizer que a programação não lida apenas com a própria escrita do código. Também envolve a utilização de estruturas de dados e algoritmos e, em geral, lidar com o panorama geral da criação e desenvolvimento de sistemas complexos.</p><h2 id="a-diferen-a-entre-escrever-c-digo-e-programar"><strong>A diferença entre escrever código e programar</strong></h2><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/fresh--2-.png" class="kg-image" alt="fresh--2-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/10/fresh--2-.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/10/fresh--2-.png 663w" width="663" height="398" loading="lazy"></figure><p>Vamos dividir as diferenças em quatro categorias principais, o que nos vai ajudar a decompor os conceitos e compreendê-los melhor.</p><h3 id="a-terminologia"><strong>A terminologia</strong></h3><p><em><strong>Escrever código</strong></em> lida com colocar o código numa linguagem compreendida tanto por máquinas como por humanos. O foco principal da escrita de código é fornecer comunicação entre os dois (humanos e computadores).</p><p><em><em><strong><strong>Program</strong></strong></em><strong>ação</strong></em> envolve criar perfil e estrutura para o código de um programa, que segue determinados padrões, antes de o código em si ser escrito para realizar a tarefa que necessita realizar.</p><h3 id="as-ferramentas-que-utilizas"><strong>As ferramentas que utilizas</strong></h3><p>No que diz respeito a <em><strong>escrita de código</strong></em>, uma das ferramentas mais importantes será o teu editor de texto (como o Bloco de notas, ou algo mais complexo e rico em funcionalidades, como o Visual Studio Code, Sublime, Atom ou Vim).</p><p>Quando falamos de <em><strong>p</strong><em><strong><strong>rogram</strong></strong></em><strong>ação</strong></em>, por outro lado, precisas adicionar algumas outras ferramentas. Como programador/a, irás realizar revisões de documentos, fazer muito planeamento, pensar em design e assim adiante.</p><p>Para te ajudar nestas tarefas, vais utilizar ferramentas como editores de código mais avançados, ferramentas de análise, depuradores, <em>frameworks </em>de modelação, ferramentas de montagem, algoritmos de modelação e muito mais.</p><p>Como programador/a, vais precisar de ter muita experiência a utilizar estas ferramentas e mais exposição ao processo que os programadores utilizam para criar aplicações e outros produtos.</p><h3 id="o-teu-n-vel-de-conhecimentos"><strong>O teu nível de conhecimentos</strong></h3><p>Como <em><strong>escritor/a de código,</strong></em> ter conhecimentos básicos de uma linguagem de programação e a sua sintaxe é um bom começo. Assim que souberes como escrever código numa linguagem, fica mais fácil aprender outras. Novamente, o teu principal objetivo está na escrita no próprio código que indica à máquina o que fazer.</p><p>Por outro lado, os/as <em><em><strong><strong>program</strong></strong></em><strong>adores/as</strong></em> precisam de mais conhecimentos. Vais precisar de saber como criar e trabalhar com algoritmos, como desenhar sites, como depurar e testar o teu código, como gerir projetos, e claro, como trabalhar com outras linguagens de programação.</p><p>Resolução de problemas, pensamento crítico e habilidades analíticas também são coisas essenciais quando estás a desenvolver sistemas complexos.</p><h3 id="o-produto-final"><strong>O produto final</strong></h3><p>Como <em><strong>escritor/a de código,</strong></em> o teu resultado esperado é geralmente uma solução simples que, depois de compilada, irá reproduzir com sucesso o resultado desejado. Um bom exemplo é o que demos anteriormente – converter um PDF num ficheiro de áudio.</p><p>Por outro lado, os/as <em><em><strong><strong>program</strong></strong></em><strong>adores/as</strong></em> vão trabalhar para fornecer uma aplicação completa funcional ou um pedaço de software que as pessoas vão utilizar no mercado. Também serão responsáveis por dar seguimento e fazer a manutenção do que criaram para garantir que está a funcionar suavemente, sem nenhum problema.</p><h2 id="como-a-escrita-de-c-digo-e-a-programa-o-trabalham-em-conjunto"><strong>Como a escrita de código e a programação trabalham em conjunto</strong></h2><p>Por esta altura, espero que sejas capaz de dizer a diferença entre escrita de código e programação e com o que estas duas coisas lidam. Agora, vamos ver como as duas podem (e devem) trabalhar em conjunto para alcançar muita coisa.</p><p>Para compreender melhor o como, vamos começar por fornecer um cenário real, onde ambas, escrita de código e programação, vão ter de trabalhar em conjunto para produzir uma aplicação funcional completa.</p><p>Imagina que te deram a tarefa de criar uma aplicação que irá ajudar a gerir ou acompanhar a tua rotina diária ou estar a par das tuas despesas diárias. Ao utilizar os conceitos dos dois mundos, podemos realizar a tarefa.</p><p>Vais precisar de um/a programador/a, que será capaz de:</p><ul><li>Planear a estrutura da aplicação (<em>com a ajuda de ferramentas como o<em> Trello</em></em>)</li><li>Escrever as principais funcionalidades da aplicação, qual a utilização esperada por parte dos utilizadores, etc.</li><li>Desenhar a aplicação (<em>ao utilizar ferramentas como<em> Figma o</em>u<em> Adobexd</em></em>)</li></ul><p>Após completar estes passos, entra o trabalho do/a escritor/a de código. Eles recebem as ideias que o/a programador/a cria e transformam-nas num formato legível para máquinas ao escrever código para realizar as tarefas especificadas. Depois do passo mágico da escrita do código, o/a programador/a volta novamente ao trabalho.</p><p>Então, o/a programador/a, irá analisar o código e verificar se existem erros, executará testes e verificará se está tudo a funcionar corretamente e que o código gera o resultado esperado. Se tudo isto se verificar, a aplicação está agora pronta para lançamento e manutenção – que permanece nas mãos do/a programador/a.</p><p>Este simples exemplo explica como as duas habilidades podem ser utilizadas em conjunto para melhor produtividade.</p><p>Apenas um apontamento final: um/a "escritor/a de código" e um/a "programador/a" nem sempre são duas pessoas distintas. Pode ser que a mesma pessoa realize todas as tarefas.</p><h2 id="resumindo"><strong>Resumindo</strong></h2><p>Onde nos enquadramos nestes dois mundos? Levei bastante tempo a perceber o que realmente me interessa.</p><p>Se tiveres mais interesse na lógica, tenta focar as tuas forças em todo o processo da programação. Se simplesmente gostares de ler e escrever código, então investe o teu tempo nisso.</p><p>Como sabemos, a ciência da computação é um campo muito amplo e ainda em desenvolvimento. Trabalha em encontrar o caminho que desejas explorar e foca-te nisso – certifica-te apenas que também desfrutas e te divertes.</p><p>Se ainda estiveres com dificuldades, espero que este artigo te tenha dado algumas luzes e ajudado a encontrar o teu caminho.</p><p>Obrigado por leres até aqui. Se tiveres gostado deste artigo, por favor compartilha-o para que possas ajudar outro programador (ou escritor de código) a encontrar o seu caminho.</p><p>Entra em contacto com o autor nas redes sociais: <a href="https://twitter.com/larymak1">Twitter</a> | <a href="https://www.linkedin.com/in/hillary-nyakundi-3a64b11ab/">LinkedIn</a> | <a href="https://github.com/larymak">GitHub</a></p><p>Desfruta da programação ❤</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Comentários no código: o bom, o mau e o feio ]]>
                </title>
                <description>
                    <![CDATA[ Me interrompa agora se você já ouviu isso antes… > "O código bom é aquele que se autodocumenta." Em mais de 20 anos escrevendo código como profissão, essa foi uma das expressões que eu mais ouvi. É um clichê daqueles. Assim como vários outros clichês, há um fundo de verdade ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/comentarios-no-codigo-o-bom-o-mau-e-o-feio/</link>
                <guid isPermaLink="false">651bf0d9f57fe803e4aa3429</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Wed, 04 Oct 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/1_ddM-OL7PF36NZ6QYCa95bQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/code-comments-the-good-the-bad-and-the-ugly-be9cc65fbf83/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">https://www.freecodecamp.org/news/code-comments-the-good-the-bad-and-the-ugly-be9cc65fbf83/</a>
      </p><p>Me interrompa agora se você já ouviu isso antes…</p><blockquote>"O código bom é aquele que se autodocumenta."</blockquote><p>Em mais de 20 anos escrevendo código como profissão, essa foi uma das expressões que eu mais ouvi.</p><p>É um <em><em>clich</em>ê </em>daqueles<em><em>.</em></em></p><p>Assim como vários outros clichês, há um fundo de verdade aí. Essa verdade, contudo, já foi muito massacrada por pessoas que disseram a frase sem ter ideia do que ela significava.</p><p>É verdade? <strong>Com certeza</strong>.</p><p>Quer dizer que você jamais deve fazer comentários no seu próprio código? <strong><strong>N</strong>ã<strong>o</strong></strong>.</p><p>Neste artigo, veremos o que é bom, o que é mau e o que é simplesmente feio quando falamos em comentários no código.</p><p>Para começar, há dois tipos diferentes de comentários no código. Eu os chamo de <strong>comentários de d<strong>ocumenta</strong>ção</strong> e <strong><strong>c</strong>omentários de esclarecimento</strong>.</p><h3 id="coment-rios-de-documenta-o"><strong>Comentários de documentação</strong></h3><p>Os comentários da documentação destinam-se a qualquer pessoa que provavelmente consumirá seu código-fonte, mas que provavelmente não o lerá. Se você estiver criando uma biblioteca ou <em>framework </em>que outros desenvolvedores usarão, você precisará de alguma forma de documentação de API.</p><p>Quanto mais distante do código-fonte a documentação da API estiver, maior a probabilidade de ela se tornar desatualizada ou imprecisa ao longo do tempo. Uma boa estratégia para reduzir esse problema é incorporar a documentação diretamente no código e, em seguida, usar uma ferramenta para extraí-la.</p><p>Aqui temos um exemplo de comentário de documentação extraída de uma biblioteca conhecida do JavaScript, chamada <a href="https://lodash.com/" rel="noopener">Lodash</a> (em inglês).</p><p>Se você <a href="https://lodash.com/docs/#countBy" rel="noopener">comparar os comentários com o que está na documentação on-line</a> (em inglês), perceberá uma correspondência exata.</p><p>Se você escrever comentários de documentação, deve garantir que eles sigam um padrão consistente e que sejam facilmente distinguíveis de quaisquer comentários de esclarecimento incluídos e que você também queira adicionar. Alguns padrões e ferramentas populares e bem suportados incluem <a href="http://usejsdoc.org/">JSDoc</a> para JavaScript, <a href="https://github.com/dotnet/docfx">DocFx</a> para dotNet e <a href="http://www.oracle.com/technetwork/java/javase/documentation/index-jsp-135444.html">JavaDoc</a> para Java.</p><p>A desvantagem desses tipos de comentários é que eles podem tornar seu código muito "cheio de ruído" e mais difícil de ler para qualquer pessoa que esteja ativamente envolvida na manutenção do código. A boa notícia é que a maioria dos editores de código suporta o "dobramento de código", que nos permite recolher os comentários para que possamos nos concentrar no código.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/10/1_o9d-IZKFtlHf4ycY_n4H2Q.gif" class="kg-image" alt="1_o9d-IZKFtlHf4ycY_n4H2Q" width="761" height="241" loading="lazy"><figcaption>Recolhimento dos comentários usando "dobramento de código" no Visual Studio Code.</figcaption></figure><h3 id="coment-rios-de-esclarecimento"><strong>Comentários de esclarecimento</strong></h3><p>Os comentários de esclarecimento destinam-se a qualquer pessoa (incluindo o seu futuro eu) que possa precisar de manter, refatorar ou estender o seu código.</p><p>Muitas vezes, um comentário de esclarecimento pode mostrar que o código "cheira mal". Ele pode significar que o seu código é muito complexo. Você deve se esforçar para remover comentários de esclarecimento e simplificar o código, porque "o código bom é aquele que se autodocumenta".</p><p>Aqui está um <a href="http://stackoverflow.com/a/766363">exemplo</a> (em inglês) de um comentário de esclarecimento ruim – embora muito divertido.</p><pre><code>/*  * Replaces with spaces  * the braces in cases  * where braces in places  * cause stasis.**/ $str = str_replace(array("\{","\}")," ",$str);</code></pre><p>Em vez de decorar uma frase levemente confusa com uma rima inteligente — e em <em><a href="https://pt.wikipedia.org/wiki/Ritmo_no_poema">anfíbraco</a></em>, surpreendentemente — o autor se daria muito melhor se tivesse se dedicado a uma função que tornasse o próprio código mais fácil de ler e de entender. Quem sabe se uma função chamada <code>removerChaves</code> chamasse outra função chamada <code>limparOInput</code>?</p><p>Não me entenda mal. Há momentos – especialmente quando você está passando por uma carga de trabalho esmagadora – em que colocar um pouco de humor pode ser bom para a alma. Porém, quando você escreve um comentário engraçado para compensar o código ruim, isso realmente torna as pessoas menos propensas a refatorar e corrigir o código mais tarde.</p><p>Você realmente quer ser o responsável por roubar de todos os futuros programadores a alegria de ler aquela pequena rima inteligente? A maioria dos programadores riria e seguiria em frente, ignorando o código que "cheira mal".</p><p>Há também momentos em que você se depara com um comentário que é redundante. Se o código já é simples e óbvio, não há necessidade de adicionar um comentário.</p><p>Por exemplo, evite usar algo como isto:</p><pre><code>/*Define o valor do inteiro idade como 32*/int idade = 32;</code></pre><p>Ainda assim, há vezes em que, não importando o que você fez com o próprio código, um comentário de esclarecimento ainda é uma boa pedida.</p><p>Isso geralmente acontece quando é preciso adicionar um pouco de contexto a uma solução contraintuitiva.</p><p>Aqui, temos um bom exemplo do próprio Lodash:</p><pre><code>function addSetEntry(set, value) {
/*  Não retorne `set.add`, pois ele não é
	encadeável no IE 11.  */
	set.add(value);
    return set;
}</code></pre><p>Também há momentos em que, depois de muita reflexão e experimentação, verifica-se que a solução aparentemente ingênua para um problema é realmente a melhor. Nesses cenários, é quase inevitável que algum outro programador venha achando que é muito mais inteligente do que você e comece a mexer com o código, apenas para descobrir que o seu caminho foi o melhor o tempo todo.</p><p>Às vezes, esse outro programador é o seu eu futuro.</p><p>Nesses casos, o melhor é poupar tempo e constrangimento de todos e deixar um comentário.</p><p>O <a href="http://stackoverflow.com/a/482129" rel="noopener">comentário provocativo abaixo</a> captura esse cenário com perfeição:</p><pre><code>/**Caro mantenedor: ao terminar de tentar 'otimizar' este programa e depois de perceber o erro terrível que cometeu, lembre-se de incrementar o seguinte contador como um aviso para a próxima vítima: total_de_horas_perdidas_aqui = 42**/</code></pre><p>O comentário acima tem mais a ver com ser engraçado do que ser útil. Você, no entanto, DEVE deixar um comentário alertando os outros para não buscarem alguma "solução melhor" aparentemente óbvia, se você já tentou diversas e viu que não davam certo. Quando você fizer isso, o comentário deve especificar qual solução você tentou e por que você decidiu não usá-la.</p><p>Aqui está um exemplo simples em JavaScript:</p><pre><code>/* Não use o isFinite() global porque ele retorna true para valores nulos*/
Number.isFinite(value)</code></pre><h3 id="o-feio"><strong>O feio</strong></h3><p>Bem, já vimos o bom e o mau. Vamos, agora, ver o feio.</p><p>Infelizmente, há momentos em qualquer trabalho em que você se verá frustrado e quando você escreve código como profissão, pode ser tentador desabafar essa frustração em comentários no código.</p><p>Trabalhando com bases de código suficientes, você encontrará comentários que variam de cínicos e deprimentes a sombrios e maldosos.</p><p>Há alguns que podem <a href="http://stackoverflow.com/a/185550" rel="noopener">parecer inofensivos</a>… (original em inglês)</p><pre><code>/*Este código é uma droga, você e eu sabemos disso. Apenas siga em frente e me xingue mais tarde.*/</code></pre><p>…e outros que são <a href="http://stackoverflow.com/a/184673" rel="noopener">simplesmente maléficos</a> (original em inglês)</p><pre><code>/* Classe usada para contornar o fato de que o Richard é um idiota sem tamanho*/</code></pre><p>Essas coisas podem parecer engraçadas ou podem ajudar a liberar um pouco de frustração no momento, mas quando elas entram no código de produção, acabam fazendo com que o programador que as escreveu e seu empregador pareçam pouco profissionais e amargos.</p><p>Não faça isso.</p><p>Se gostou deste artigo, compartilhe-o com seus colegas de trabalho. Se quiser ler mais (em inglês) sobre o assunto do artigo, assine a <em>newsletter </em>semanal do autor no site <a href="https://devmastery.com/">Dev Mastery</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Herança múltipla em C++ e o problema do diamante ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Onur Tuna Ao contrário de muitas outras linguagens de programação orientada a objetos, o C++ permite várias heranças. A herança múltipla permite que uma classe filho herde de mais de uma classe pai. No início, parece um recurso muito útil. Um usuário, porém, precisa estar atento a algumas ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/heranca-multipla-em-c-mais-mais-e-o-problema-do-diamante/</link>
                <guid isPermaLink="false">64f509bb9566cf03c3d54228</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Sun, 03 Sep 2023 23:07:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/09/1_QVZomxLNxnRYhm9gGIfYyw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/multiple-inheritance-in-c-and-the-diamond-problem-7c12a9ddbbec/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Multiple Inheritance in C++ and the Diamond Problem</a>
      </p><p>Escrito por: Onur Tuna</p><p>Ao contrário de muitas outras linguagens de programação orientada a objetos, o C++ permite várias heranças.</p><p>A herança múltipla permite que uma classe filho herde de mais de uma classe pai.</p><p>No início, parece um recurso muito útil. Um usuário, porém, precisa estar atento a algumas dificuldades ao implementar esse recurso.</p><p>Nos exemplos abaixo, abordaremos alguns cenários sobre os quais é preciso estar atento.</p><p>Começaremos com um exemplo simples para explicar esse conceito em C++.</p><pre><code>#include &lt;iostream&gt;

class SerVivo {
protected:
    void respirar() {
        std::cout &lt;&lt; "Respiro como um ser vivo." &lt;&lt; std::endl;
    }
};

class Animal : protected SerVivo {
protected:
    void respirar() {
        std::cout &lt;&lt; "Respiro como um animal." &lt;&lt; std::endl;
    }
};

class Reptil : protected SerVivo {
protected:
    void rastejar() {
        std::cout &lt;&lt; "Rastejo como um réptil." &lt;&lt; std::endl;
    }
};

class Cobra : protected Animal, protected Reptil {
public:
    void respirar() {
        std::cout &lt;&lt; "Respiro como uma cobra." &lt;&lt; std::endl;
    }

    void rastejar() {
        std::cout &lt;&lt; "Rastejo como uma cobra." &lt;&lt; std::endl;
    }
};

int main() {
    Cobra cobra;

    cobra.respirar();
    cobra.rastejar();

    return 0;
}</code></pre><p>A saída desse código é a seguinte:</p><pre><code>Respiro como uma cobra.
Rastejo como uma cobra.</code></pre><p>No exemplo acima, temos uma classe base chamada <strong>SerVivo</strong>. As classes <strong><strong>Animal</strong></strong><em><em> </em></em>e <strong><strong>Reptil</strong></strong> herdam dela. Somente a classe <strong><strong>Animal</strong></strong><em><em> </em></em>sobrescreve o método <code>respirar()</code>. A classe <strong>Cobra</strong> herda das classes <strong><strong>Animal</strong></strong> e <strong><strong>Reptil</strong></strong>. Ela sobrescreve seus métodos. Acima, não vemos problemas. O código funciona bem.</p><p>Agora, vamos deixar as coisas um pouco mais complexas.</p><p>O que ocorreria se a classe <strong><strong>Reptil</strong></strong> sobrescrevesse o método <code>respirar()</code>?</p><p>A classe <strong>Cobra</strong> não saberia qual método <code>respirar()</code> deve ser chamado. Esse é o "Problema do diamante".</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/09/1_cI0TQYv7yOgSsHhfES1Kaw.png" class="kg-image" alt="1_cI0TQYv7yOgSsHhfES1Kaw" width="563" height="640" loading="lazy"></figure><h4 id="problema-do-diamante"><strong>Problema do diamante</strong></h4><p>Veja o código abaixo. É como o código no exemplo acima, com a diferença que sobrescrevemos o método <code>respirar()</code> na classe <strong><strong>Reptil</strong></strong>.</p><pre><code>#include &lt;iostream&gt;

class SerVivo {
protected:
    void respirar() {
        std::cout &lt;&lt; "Respiro como um ser vivo." &lt;&lt; std::endl;
    }
};

class Animal : protected SerVivo {
protected:
    void respirar() {
        std::cout &lt;&lt; "Respiro como um animal." &lt;&lt; std::endl;
    }
};

class Reptil : protected SerVivo {
public:
    void respirar() {
        std::cout &lt;&lt; "Respiro como um réptil." &lt;&lt; std::endl;
    }

    void rastejar() {
        std::cout &lt;&lt; "Rastejo como um réptil." &lt;&lt; std::endl;
    }
};

class Cobra : public Animal, public Reptil {

};

int main() {
    Cobra cobra;

    cobra.respirar();
    cobra.rastejar();

    return 0;
}</code></pre><p>Se tentar compilar esse programa, ele não funcionará. Você verá uma mensagem de erro como a seguinte.</p><figure class="kg-card kg-code-card"><pre><code>member ‘respirar’ found in multiple base classes of different types</code></pre><figcaption>Tradução: membro 'respirar' encontrado em várias classes de base de tipos diferentes</figcaption></figure><p>O erro tem a ver com o "Problema do diamante" da herança múltipla. A classe <strong>Cobra </strong>não sabe qual método <code>respirar()</code> deve ser chamado.</p><p>No primeiro exemplo, apenas a classe <strong><strong>Animal</strong></strong> sobrescrevia o método <code>respirar()</code>. A classe <strong><strong>Reptil</strong></strong> class não fazia isso. Assim, não era problema para a classe <strong>Cobra</strong> saber qual método <code>respirar()</code> deveria ser chamado. A classe <strong>Cobra</strong> acabaria chamando o método <code>respirar()</code> da classe <strong><strong>Animal</strong></strong>.</p><p>No segundo exemplo, a classe Cobra herda <strong>dois</strong> métodos <code>respirar()</code>: o método <code>respirar()</code> das classes <strong><strong>Animal</strong></strong> e <strong><strong>Reptil</strong></strong>. Como não sobrescrevemos o método <code>respirar()</code> na classe <strong>Cobra</strong>, acabamos com uma ambiguidade.</p><p>O C++ tem muitos recursos poderosos, como a herança múltipla. Porém, não é necessário usarmos todos os recursos que ele oferece.</p><p>Prefiro não usar herança múltipla e usar a herança <em><em>virtual</em></em> em vez dela.</p><p>A herança virtual <em>resolve </em>o clássico "Problema do diamante”. Ela garante que a classe filho receba apenas uma única instância da classe base comum.</p><p>Em outras palavras, a classe <strong>Cobra</strong> teria apenas <strong>uma</strong> instância da classe <strong>SerVivo</strong>. As classes <strong><strong>Animal</strong></strong> e <strong><strong>Reptil</strong></strong> compartilhariam essa instância.</p><p>Isso resolve o erro de tempo de compilação que recebemos anteriormente. As classes derivadas das classes abstratas devem sobrescrever as funções virtuais puras definidas na classe base.</p><p>Esperamos que tenha gostado dessa visão geral de heranças múltiplas e do "Problema do diamante".</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Aqui estão algumas ideias de aplicações que você pode criar para elevar o nível de suas habilidades de programação ]]>
                </title>
                <description>
                    <![CDATA[ Você já quis criar algo, mas não tinha ideia do que fazer? Assim como os autores, às vezes, têm "bloqueio de escritor", isso também é verdade para os desenvolvedores. Juntamente com meu amigo Jim [https://twitter.com/jd_medlock], criamos uma  coleção de ideias de aplicações [https://github.com/florinpop17/app-ideas] que se destina a resolver esse ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/aqui-estao-algumas-ideias-de-aplicacoes-que-voce-pode-criar-para-elevar-o-nivel-de-suas-habilidades-de-programacao/</link>
                <guid isPermaLink="false">641d77c402ec1d064260e67a</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Tue, 13 Jun 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/05/0_v3qXmKe1LTiiW_3H.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/here-are-some-app-ideas-you-can-build-to-level-up-your-coding-skills-39618291f672/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Here are some app ideas you can build to level up your coding skills</a>
      </p><p>Você já quis criar algo, mas não tinha ideia do que fazer? Assim como os autores, às vezes, têm "bloqueio de escritor", isso também é verdade para os desenvolvedores.</p><p>Juntamente com meu amigo <a href="https://twitter.com/jd_medlock">Jim</a>, criamos uma <a href="https://github.com/florinpop17/app-ideas">coleção de ideias de aplicações</a> que se destina a resolver esse problema de uma vez por todas!</p><p>Essas aplicações são:</p><ul><li>ótimas para aprimorar suas habilidades de programação</li><li>ótimas para dar experiência com novas tecnologias</li><li>ótimas para serem adicionadas ao seu portfólio para impressionar seu próximo empregador/cliente</li><li>ótimas para serem usadas como exemplo em tutoriais (artigos ou vídeos)</li><li>fáceis de completar e também facilmente ampliáveis com novos recursos</li></ul><p>Esta não é apenas uma simples lista de projetos, mas uma coleção que descreve cada projeto com detalhes suficientes para que você possa desenvolvê-los do zero!</p><p>Cada especificação de projeto contém o seguinte:</p><ol><li>Um objetivo claro e descritivo</li><li>Uma lista de <em>histórias de usuários</em> que devem ser implementadas. Essas histórias atuam mais como uma diretriz do que como uma lista forçada de <em>tarefas pendentes</em> – sinta-se à vontade para adicionar seus próprios recursos, se desejar</li><li>Uma lista de <em>recursos adicionais</em> que aprimoram não apenas o projeto básico, mas também suas habilidades ao mesmo tempo</li><li>Todos os recursos e links para ajudá-lo a encontrar o que você precisa para concluir o projeto</li></ol><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/TNzCfgwIDCY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="80+ Application Ideas for Developers" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><h3 id="projetos"><strong><strong>Proje</strong>tos</strong></h3><p>Todos os projetos são divididos em três níveis com base no conhecimento e na experiência necessários para concluí-los. Esses níveis são:</p><ol><li><strong>Iniciante</strong> – Desenvolvedores nos estágios iniciais de sua jornada de aprendizado. Aqueles que normalmente se concentram na criação de aplicações voltadas para o usuário.</li><li><strong>Intermediário</strong> – Desenvolvedores em um estágio intermediário de aprendizado e experiência. Eles se sentem confortáveis em UI/UX, usando ferramentas de desenvolvimento e criando aplicações que usam serviços de API.</li><li><strong>Avançado</strong> – Desenvolvedores que têm todos os conhecimentos acima e estão aprendendo técnicas mais avançadas, como a implementação de aplicações de back-end e serviços de banco de dados.</li></ol><p>Abaixo, você encontrará <strong>5 projetos </strong>para cada uma das camadas (<strong>15 no total</strong>), mas há mais de <strong>30 projetos</strong> (no momento) neste <a href="https://github.com/florinpop17/app-ideas">repositório do GitHub</a>. Não deixe de conferir, pois estamos planejando adicionar mais projetos no futuro. Sua ajuda é bem-vinda! Mais informações sobre isso na seção <em>Contribuição</em> abaixo.</p><h3 id="1-aplica-o-de-notas"><strong>1. Aplicação de notas</strong></h3><p><strong>Nível</strong>: 1 - Iniciante</p><p><strong>Descrição</strong>: Crie e armazene suas anotações para uso posterior!</p><h3 id="hist-rias-de-usu-rio"><strong>Histórias de usuário</strong></h3><ul><li>O usuário pode criar uma nota</li><li>O usuário pode editar uma nota</li><li>O usuário pode excluir uma nota</li><li>Ao fechar a janela do navegador, as anotações serão armazenadas e, quando o usuário retornar, os dados serão recuperados</li></ul><h3 id="recursos-adicionais"><strong>Recursos adicionais</strong></h3><ul><li>O usuário pode criar e editar uma nota no formato <em>markdown</em>. Ao salvar, ele converterá <em>markdown</em> em HTML</li><li>O usuário pode ver a data em que criou a nota</li></ul><h3 id="links-e-recursos-teis"><strong>Links e recursos úteis</strong></h3><ul><li><a href="https://developer.mozilla.org/pt-BR/docs/Web/API/Window/localStorage">localStorage</a></li><li><a href="https://www.markdownguide.org/basic-syntax/">Guia de Markdown</a> (em inglês)</li><li><a href="https://github.com/markedjs/marked">Marked – um parser de markdown</a> (instruções do projeto em inglês)</li></ul><p><strong><strong>Ex</strong>emplo de<strong> proje</strong>to</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_gbyygq" src="https://codepen.io/nickmoreton/embed/preview/gbyygq?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=gbyygq" title="AngularJS Markdown Notes App" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h3 id="2-luzes-de-natal"><strong><strong>2.</strong> </strong>Luzes de Natal</h3><p><strong>Nível</strong>: 1 - Iniciante</p><p><strong>Descrição</strong>: a aplicação de Luzes de Natal depende de seus talentos de desenvolvimento para criar uma exibição de luzes hipnotizantes. Sua tarefa é desenhar sete círculos coloridos em uma fileira e, com base em um cronômetro, alterar a intensidade de cada círculo. Quando um círculo é iluminado, seu antecessor retorna à intensidade normal.</p><p>Isso simula o efeito de uma série de luzes piscantes, semelhante às exibidas durante as festas de Natal.</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode pressionar um botão para iniciar e parar a exibição</li><li>O usuário pode alterar o intervalo de tempo que controla a mudança na intensidade</li></ul><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode selecionar a cor usada para preencher cada círculo</li><li>O usuário pode especificar o valor da intensidade</li><li>O usuário pode alterar o tamanho de qualquer círculo na linha</li><li>O usuário pode especificar o número de linhas a serem incluídas na exibição, podendo escolher de uma a sete linhas</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://previews.123rf.com/images/whiterabbit/whiterabbit1003/whiterabbit100300020/6582600-seven-color-balls-red-orange-yellow-green-cyan-blue-and-magenta-in-a-row-on-a-white-background.jpg">Imagem de amostra</a></li><li><a href="https://cdn-shop.adafruit.com/970x728/1487-02.jpg" rel="noopener">Adafruit LED Matrix</a></li></ul><p><strong>Exemplo de projeto</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_QjvEex" src="https://codepen.io/tobyj/embed/preview/QjvEex?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=QjvEex" title="Pure CSS Christmas Lights" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h3 id="3-flipimage"><strong><strong>3. FlipImage</strong></strong></h3><p><strong>Nível: 1</strong> - Iniciante</p><p><strong>Descrição</strong>: É importante que os desenvolvedores da Web compreendam os fundamentos da manipulação de imagens, pois as aplicações avançadas da Web dependem de imagens para agregar valor à interface e à experiência do usuário (UI/UX).</p><p>O FlipImage explora um aspecto da manipulação de imagens: a rotação de imagens. Essa aplicação exibe um painel quadrado contendo uma única imagem apresentada em uma matriz 2x2. Usando um conjunto de setas para cima, para baixo, para a esquerda e para a direita adjacentes a cada uma das imagens, o usuário pode virá-las na vertical ou na horizontal.</p><p>Você deve usar somente HTML, CSS e Javascript nativos para implementar essa aplicação. Pacotes de imagens e bibliotecas não são permitidos.</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode ver um painel contendo uma única imagem repetida em uma matriz 2x2</li><li>O usuário pode virar qualquer uma das imagens na vertical ou na horizontal usando um conjunto de setas para cima, para baixo, para a esquerda e para a direita ao lado da imagem</li></ul><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode alterar a imagem padrão inserindo o URL de uma imagem diferente em um campo de entrada</li><li>O usuário pode exibir a nova imagem clicando no botão "Display" (Exibir) ao lado do campo de entrada</li><li>O usuário poderá ver uma mensagem de erro se o URL das novas imagens não for encontrado</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://www.w3schools.com/howto/howto_css_flip_image.asp">Como virar uma imagem</a> (em inglês)</li><li><a href="https://davidwalsh.name/css-flip">Criando uma animação de inversão de CSS</a> (em inglês)</li></ul><p><strong>Exemplo de projeto</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_gvqYQv" src="https://codepen.io/seyedi/embed/preview/gvqYQv?default-tabs=html%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=gvqYQv" title="Image Effects" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h3 id="4-aplica-o-de-question-rio"><strong><strong>4. </strong></strong>Aplicação de questionário</h3><p><strong>Nível: 1</strong> - Iniciante</p><p><strong>Descrição:</strong> Pratique e teste seus conhecimentos respondendo a perguntas em uma aplicação de questionário.</p><p>Como desenvolvedor, você pode criar uma aplicação de questionário para testar as habilidades em programação de outros desenvolvedores (em HTML, CSS, JavaScript, Python, PHP etc.)</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode iniciar o questionário pressionando um botão</li><li>O usuário pode ver uma pergunta com 4 respostas possíveis</li><li>Depois de selecionar uma resposta, exiba a próxima pergunta para o usuário. Faça isso até que o questionário seja concluído</li><li>No final, o usuário pode ver as seguintes estatísticas:</li></ul><ol><li>Tempo necessário para concluir o questionário</li><li>Quantas respostas corretas ele obteve?</li><li>Uma mensagem mostrando se ele foi aprovado ou reprovado no teste</li></ol><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode compartilhar o resultado de um questionário nas mídias sociais</li><li>Adicione vários testes à aplicação. O usuário pode selecionar quais deles deseja responder</li><li>O usuário pode criar uma conta e ter todas as pontuações salvas em seu painel</li><li>O usuário pode concluir um questionário várias vezes</li></ul><h4 id="links-e-recursos-teis-1"><strong>Links e recursos úteis</strong></h4><ul><li><a href="https://opentdb.com/api_config.php">Abrir banco de dados de curiosidades</a> (em inglês)</li></ul><p><strong>Exemplos de projetos</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_qqYNgW" src="https://codepen.io/FlorinPop17/embed/preview/qqYNgW?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=qqYNgW" title="Quiz app interface" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p><a href="http://tranquil-beyond-43849.herokuapp.com/">Aplicação de questionário criada com React</a> (aguarde o carregamento, pois ela está hospedada no Heroku)</p><h3 id="5-conversor-de-n-meros-romanos-para-decimais"><strong>5. Conversor de números romanos para decimais</strong></h3><p><strong>Nível: 1</strong> - Iniciante</p><p><strong>Descrição</strong>: O sistema numérico representado pelos algarismos romanos teve origem na Roma antiga e continuou sendo a forma usual de escrever números em toda a Europa até o final da Idade Média. Os números romanos, como usados atualmente, empregam sete símbolos, cada um com um valor inteiro fixo.</p><p>Veja na tabela abaixo o <em>Símbolo</em> - <em>pares de Valores</em>:</p><ul><li>I — 1</li><li>V — 5</li><li>X — 10</li><li>L — 50</li><li>C — 100</li><li>D — 500</li><li>M — 1000</li></ul><p><strong>Histórias de usuário</strong></p><ul><li>O usuário deve ser capaz de inserir um número romano em um campo de entrada</li><li>O usuário poderá ver os resultados em um único campo de saída contendo o equivalente decimal (base 10) do número romano que foi inserido ao pressionar um botão</li><li>Se um símbolo errado for inserido, o usuário deverá ver um erro</li></ul><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode ver a conversão ser feita automaticamente ao digitar</li><li>O usuário deve ser capaz de converter de decimal para romano (e vice-versa)</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://pt.wikipedia.org/wiki/Numera%C3%A7%C3%A3o_romana">Uma explicação sobre os números romanos</a></li></ul><p><strong>Exemplo de projeto</strong></p><p><a href="https://www.calculatorsoup.com/calculators/conversions/roman-numeral-converter.php">Conversor de números romanos</a> (instruções em inglês)</p><h3 id="6-aplica-o-localizadora-de-livros"><strong>6. Aplicação localizadora de livros</strong></h3><p><strong>Nível: 2</strong> - Intermediário</p><p><strong>Descrição:</strong> Criar uma aplicação que permita aos usuários pesquisar livros inserindo uma consulta (título, autor etc.). Exibir os livros resultantes em uma lista na página com todos os dados correspondentes.</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode inserir uma consulta de pesquisa em um campo de entrada</li><li>O usuário pode enviar a consulta. Isso chamará uma API que retornará um array de livros com os dados correspondentes (<strong>título, autor, data de publicação, imagem</strong> etc.)</li><li>O usuário pode ver a lista de livros que aparecem na página</li></ul><p><strong>Recursos adicionais</strong></p><ul><li>Para cada item da lista, adicionar um link que enviará o usuário a um site externo que tenha mais informações sobre o livro</li><li>Implementar um design responsivo</li><li>Adicionar animações de carregamento</li></ul><p><strong>Links e recursos úteis</strong></p><p>Você pode usar a <a href="https://developers.google.com/books/docs/overview">API do Google Livros</a></p><p><strong>Exemplo de projeto</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_wpQBKV" src="https://codepen.io/chasebank/embed/preview/wpQBKV?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=wpQBKV" title="Vue, Axios and Google Books" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p><a href="https://fethica.github.io/BookSearch-React/">Busca de Livros - React</a></p><h3 id="7-jogo-de-mem-ria-de-cartas"><strong>7. Jogo de memória de cartas</strong></h3><p><strong>Nível: 2</strong> - Intermediário</p><p><strong>Descrição</strong>: O jogo de memória de cartas é um jogo em que você precisa clicar em uma carta para ver a imagem que está embaixo dela e tentar encontrar a imagem correspondente embaixo das outras cartas.</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode ver uma grade com n x n cartas (n é um número inteiro), sendo que todas as cartas estão inicialmente viradas para baixo (estado oculto)</li><li>O usuário pode clicar em um botão para iniciar o jogo e, quando esse botão for clicado, um cronômetro será iniciado</li><li>O usuário pode clicar em qualquer carta para revelar a imagem que está embaixo dela (alterá-la para o estado visível). A imagem será exibida até que o usuário clique em uma segunda carta</li></ul><p>Quando o usuário clica na segunda carta:</p><ul><li>Se houver uma correspondência, as duas cartas serão eliminadas do jogo (seja escondendo-as/removendo-as ou deixando-as visíveis)</li><li>Se não houver uma correspondência, as duas cartas voltarão ao seu estado original (estado oculto)</li><li>Quando todas as correspondências tiverem sido encontradas, o usuário poderá ver uma caixa de diálogo com uma mensagem de parabéns e um contador mostrando o tempo que levou para terminar o jogo</li></ul><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode escolher entre vários níveis de dificuldade (Fácil, Médio, Difícil). Aumentar a dificuldade significa: diminuir o tempo disponível para concluir e/ou aumentar o número de cartas</li><li>O usuário pode ver as estatísticas do jogo (número de vezes que ganhou/perdeu, o melhor tempo para cada nível)</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://en.wikipedia.org/wiki/Concentration_(game)" rel="noopener">Wikipédia</a> (em inglês)</li></ul><p><strong>Exemplos de projetos</strong></p><p><a href="https://codepen.io/zerospree/full/bNWbvW">Flip - jogo de memória de cartas</a> (em inglês)</p><p><a href="https://codepen.io/hexagoncircle/full/OXBJxV">SMB3 Jogo de memória de cartas</a> (em inglês)</p><h3 id="8-gerador-de-tabelas-em-markdown"><strong>8. Gerador de tabelas em <em>markdown</em></strong></h3><p><strong>Nível: 2</strong> - Intermediário</p><p><strong>Descrição:</strong> Crie uma aplicação que converterá uma tabela normal com dados fornecidos pelo usuário (opcionalmente) em uma tabela formatada em <em>markdown</em>.</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode criar uma tabela HTML com um determinado número de <strong>linhas</strong> e <strong>colunas</strong></li><li>O usuário pode inserir texto em cada célula da tabela HTML</li><li>O usuário pode gerar uma tabela formatada em <em>markdown</em> que conterá os dados da tabela HTML</li><li>O usuário pode visualizar a tabela formatada em <em>markdown</em></li></ul><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode copiar a tabela formatada do markdown para a área de transferência pressionando um botão</li><li>O usuário pode inserir uma nova <strong>linha</strong> ou <strong>coluna</strong> em um local especificado</li><li>O usuário pode excluir uma <strong>linha</strong> ou <strong>coluna</strong> completamente</li><li>O usuário pode alinhar (<em>à esquerda, à direita ou ao centro</em>) uma <strong>célula</strong>, uma <strong>coluna</strong>, uma linha ou a <strong>tabela</strong> inteira</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://www.markdownguide.org/">Guia de markdown</a> (em inglês)</li><li><a href="https://github.com/markedjs/marked">Marked - Um analisador de markdown</a> (em inglês)</li><li><a href="https://www.w3schools.com/howto/howto_js_copy_clipboard.asp">Como copiar para a área de transferência</a> (em inglês)</li></ul><p><strong>Exemplo de projeto</strong></p><p><a href="https://www.tablesgenerator.com/markdown_tables">Gerador de tabelas/Tabelas Markdown</a> (em inglês)</p><h3 id="9-arte-com-strings"><strong><strong>9. </strong>Arte com s<strong>tring</strong>s</strong></h3><p><strong>Nível</strong>: 2 - Intermediário</p><p><strong>Descrição</strong>: O objetivo de Arte com strings é proporcionar ao desenvolvedor a prática de criar um gráfico animado simples, usando geometria no algoritmo de animação e criando algo que seja visualmente agradável de assistir.</p><p>A Arte com strings desenha uma única linha multicolorida que se move suavemente até que uma extremidade toque em um lado da janela que a envolve. No ponto em que ela toca, um efeito de "salto" é aplicado para mudar sua direção.</p><p>Um efeito de ondulação é criado mantendo apenas 10 a 20 imagens da linha à medida que ela se move. As imagens mais antigas são progressivamente desbotadas até desaparecerem.</p><p>As bibliotecas de animação não são permitidas. Use apenas HTML/CSS/JavaScript puro.</p><p><strong>Histórias de usuário</strong></p><ul><li>Comece desenhando uma linha multicolorida em uma posição aleatória dentro do limite da janela que a envolve</li><li>A cada 20 ms, desenhe uma cópia da linha em uma nova posição com base em uma trajetória – a distância incremental da linha anterior com base nos pontos finais</li><li>Quando um dos pontos de extremidade da linha tocar o limite da janela circundante, mude sua direção e altere aleatoriamente seu ângulo</li><li>Diminua progressivamente a intensidade das linhas antigas de modo que apenas as 10 a 20 linhas mais recentes fiquem visíveis para criar a sensação de movimento ou "ondulação"</li></ul><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode especificar o comprimento da linha e sua velocidade</li><li>O usuário pode especificar as várias linhas dentro da janela, todas se movendo ao longo de diferentes trajetórias e velocidades</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://css-tricks.com/using-multi-step-animations-transitions/">Uso de animações e transições de várias etapas</a> (em inglês)</li><li><a href="https://www.khanacademy.org/computing/computer-programming/programming/animation-basics/a/what-are-animations">Noções básicas de animação</a> (em inglês)</li></ul><p><strong>Exemplo de projeto</strong></p><p>Este projeto é muito próximo do que pretendemos aqui, mas tem uma pequena janela de fechamento e é monocromático. <a href="https://codepen.io/dgca/pen/dpxreO">Daniel Cortes</a></p><h3 id="10-aplica-o-de-tarefas-por-fazer"><strong><strong>10. </strong></strong>Aplicação de tarefas por fazer</h3><p><strong>Nível</strong>: 2 - Intermediário</p><p><strong>Descrição</strong>: A aplicação de tarefas clássica em que o usuário pode anotar todas as coisas que deseja realizar.</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode ver um campo de entrada no qual ele pode digitar um item de tarefa</li><li>Ao pressionar Enter (ou um botão), o usuário pode enviar o item de tarefa e pode ver que ele está sendo adicionado a uma lista de tarefas</li><li>O usuário pode marcar uma tarefa como concluída</li><li>O usuário pode remover um item de tarefa pressionando um botão (ou o próprio item de tarefa)</li></ul><p><strong>Recursos adicionais</strong></p><ul><li>O usuário pode editar uma tarefa</li><li>O usuário pode ver uma lista com todas as tarefas concluídas</li><li>O usuário pode ver uma lista com todas as tarefas ativas</li><li>O usuário pode ver a data em que criou a tarefa</li><li>Ao fechar a janela do navegador, as tarefas serão armazenadas e, quando o usuário retornar, os dados serão recuperados</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://developer.mozilla.org/pt-BR/docs/Web/API/Window/localStorage">localStorage</a> (armazenamento local)	</li></ul><p><strong>Exemplos de projetos</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_eJIuF" src="https://codepen.io/yesilfasulye/embed/preview/eJIuF?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=eJIuF" title="To Do List" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p><a href="http://todomvc.com/examples/react/#/">Aplicação de tarefas desenvolvida com React</a></p><h3 id="11-mecanismo-do-jogo-de-batalha-naval"><strong>11. Mecanismo do jogo de batalha naval</strong></h3><p><strong>Nível</strong>: 3 - Avançado</p><p><strong>Descrição</strong>: O mecanismo do jogo de batalha naval (em inglês, Battleship Game Engine, ou BGE) implementa o clássico jogo de tabuleiro baseado em turnos como um pacote separado de qualquer camada de apresentação. Esse é um tipo de padrão arquitetônico que é útil em muitas aplicações, pois permite que qualquer número de aplicações utilize o mesmo serviço.</p><p>O próprio BGE é invocado por meio de uma série de chamadas de função em vez de ações diretamente acopladas do usuário final. Nesse aspecto, o uso do BGE é semelhante ao uso de uma API ou de uma série de rotas expostas por um servidor da web.</p><p>Esse desafio exige que você desenvolva o BGE e uma camada de apresentação baseada em texto muito fina para testes, separada do próprio mecanismo. Devido a isso, as histórias de usuário abaixo estão divididas em dois conjuntos: um para o BGE e outro para a camada de apresentação baseada em texto.</p><p>O BGE é responsável por manter o estado do jogo.</p><p><strong>Histórias de usuário</strong></p><h4 id="bge"><strong><strong>BGE</strong></strong></h4><ul><li>O chamador pode invocar uma função <code>startGame()</code> para iniciar um jogo para um jogador. Essa função gerará um tabuleiro de jogo 8x8 que consiste em 3 navios com uma largura de um quadrado e um comprimento de:</li></ul><ol><li>Destroyer: 2 quadrados</li><li>Cruzador: 3 quadrados</li><li>Navio de guerra: 4 quadrados</li></ol><p><code>startGame()</code> colocará aleatoriamente esses navios no tabuleiro em qualquer direção e retornará um array que representa o posicionamento dos navios.</p><ul><li>O chamador pode invocar uma função <code>shoot()</code> passando as coordenadas de linha e coluna da célula-alvo no tabuleiro de jogo. <code>shoot()</code> retornará indicadores que representam se o tiro resultou em acerto ou erro, o número de navios restantes (ou seja, ainda não afundados), o array de posicionamento de navios e o array atualizado de acertos e erros.</li></ul><p>As células no array de acertos e erros conterão um espaço se ainda não tiverem sido alvos, O se tiverem sido alvos, mas nenhuma parte de um navio estava naquele local, ou X se a célula tiver sido ocupada por parte de um navio.</p><h4 id="camada-de-apresenta-o-baseada-em-texto"><strong>Camada de apresentação baseada em texto</strong></h4><ul><li>O usuário pode ver o array de acertos e erros exibido como uma representação bidimensional de caracteres do tabuleiro de jogo retornado pela função <code>startGame()</code>.</li><li>O usuário pode ser solicitado a inserir as coordenadas de um quadrado alvo no tabuleiro de jogo.</li><li>O usuário pode ver uma exibição atualizada do array de acertos e erros depois de dar um tiro.</li><li>O usuário pode ver uma mensagem após cada disparo, indicando se o disparo resultou em acerto ou erro.</li><li>O usuário pode ver uma mensagem de parabéns após o tiro que afunda o último navio restante.</li><li>O usuário pode ser solicitado a jogar novamente no final de cada jogo. A recusa em jogar novamente interrompe o jogo.</li></ul><p><strong>Recursos adicionais</strong></p><h4 id="bge-1"><strong><strong>BGE</strong></strong></h4><ul><li>O chamador pode especificar o número de linhas e colunas no tabuleiro do jogo como um parâmetro para a função <code>startGame()</code>.</li><li>O chamador pode invocar uma função <code>gameStats()</code> que retorna um objeto Javascript contendo métricas para o jogo atual. Por exemplo, o número de turnos jogados, o número atual de acertos e erros etc.</li><li>O chamador pode especificar o número de jogadores (1 ou 2) ao chamar <code>startGame()</code>, que gerará um tabuleiro para cada jogador preenchido aleatoriamente com navios.</li></ul><p><code>shoot()</code> aceitará o número do jogador para o qual a jogada está sendo realizada, juntamente com as coordenadas da jogada. Os dados retornados serão para esse jogador.</p><h4 id="camada-de-apresenta-o-baseada-em-texto-1">Camada de apresentação baseada em texto</h4><ul><li>O usuário pode ver as estatísticas atuais do jogo em qualquer ponto inserindo as estatísticas da frase no lugar das coordenadas do alvo. Observe que isso requer a função <code>gameStats()</code> no BGE.</li><li>O usuário pode especificar que um jogo para dois jogadores deve ser jogado, com cada jogador alternando turnos na mesma sessão de terminal (observe que isso requer os recursos de bônus correspondentes no BGE).</li><li>O usuário pode ver o número do jogador nos alertas associados às entradas em cada turno.</li><li>O usuário pode ver o tabuleiro de ambos os jogadores no final de cada turno.</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://pt.wikipedia.org/wiki/Batalha_naval_(jogo)">Jogo de Batalha Naval (Wikipédia)</a></li><li><a href="https://www.hasbro.com/common/instruct/battleship.pdf">Regras do jogo de Batalha Naval (Hasbro)</a> (em inglês)</li></ul><p><strong>Exemplo de projetos</strong></p><p>Este vídeo do YouTube (em inglês) mostra como é jogado um jogo de <a href="https://www.youtube.com/watch?v=TKksu3JXTTM">batalha naval </a>baseado em texto.</p><p>O exemplo a seguir é fornecido como uma demonstração do jogo de batalha naval, caso ele não seja familiar para você. Lembre-se de que você deve implementar uma camada de apresentação baseada em texto para teste. <a href="https://codepen.io/CodifyAcademy/pen/ByBEOz">Jogo de Batalha Naval por Chris Brody</a> (em inglês).</p><h3 id="12-aplica-o-de-bate-papo"><strong>12. Aplicação de bate-papo</strong></h3><p><strong>Nível</strong>: 3 - Avançado</p><p><strong>Descrição</strong>: Interface de bate-papo em tempo real em que vários usuários podem interagir entre si enviando mensagens.</p><p>Como MVP (Minimum Viable Product – em português, <a href="https://pt.wikipedia.org/wiki/Produto_vi%C3%A1vel_m%C3%ADnimo">produto viável mínimo</a>), você pode se concentrar na criação da interface de bate-papo. A funcionalidade em tempo real pode ser adicionada posteriormente (nos recursos adicionais).</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário é solicitado a inserir um nome de usuário quando visita a aplicação de bate-papo. O nome de usuário será armazenado na aplicação</li><li>O usuário pode ver um campo de entrada onde pode digitar uma nova mensagem</li><li>Ao pressionar a tecla Enter ou clicar no botão Enviar, o texto será exibido na caixa de bate-papo ao lado do nome de usuário (por exemplo, <code>Fulano: Olá, mundo!</code>)</li></ul><h4 id="recursos-adicionais-1"><strong>Recursos adicionais</strong></h4><ul><li>As mensagens ficarão visíveis para todos os usuários que estiverem na aplicação de bate-papo (usando WebSockets)</li><li>Quando um novo usuário entra no bate-papo, uma mensagem é exibida para todos os usuários existentes</li><li>As mensagens são salvas em um banco de dados</li><li>O usuário pode enviar imagens, vídeos e links que serão exibidos corretamente</li><li>O usuário pode selecionar e enviar um emoji</li><li>Os usuários podem conversar em particular</li><li>Os usuários podem participar de canais sobre tópicos específicos</li></ul><h4 id="links-e-recursos-teis-2"><strong>Links e recursos úteis</strong></h4><ul><li><a href="https://socket.io/" rel="noopener">Socket.io</a> (em inglês)</li><li><a href="https://www.freecodecamp.org/news/how-to-build-a-react-js-chat-app-in-10-minutes-c9233794642b">Como criar uma aplicação de bate-papo no React.js em 10 minutos - artigo</a> (em inglês)</li></ul><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/tHbCkikFfDE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Socket.io Chat App Using Websockets" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><p><strong>Exemplo de projeto</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_ZWEdZj" src="https://codepen.io/iremlopsum/embed/preview/ZWEdZj?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=ZWEdZj" title="Simple chat app using firebase" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h3 id="13-linha-do-tempo-do-github"><strong>13. Linha do tempo do GitHub</strong></h3><p><strong>Nível</strong>: 3 - Avançado</p><p><strong>Descrição</strong>: As APIs e a representação gráfica de informações são marcas registradas das aplicações modernas da web. O GitHub Timeline combina os dois para criar um histórico visual da atividade de um usuário no GitHub.</p><p>O objetivo do GitHub Timeline é aceitar um nome de usuário do GitHub e produzir uma linha do tempo contendo cada repositório, com as anotações dos nomes dos repositórios, a data em que foram criados e suas descrições. A linha do tempo deve ser compartilhada com um possível empregador. Ela deve ser fácil de ler e fazer uso eficaz de cores e tipografia.</p><p>Somente os repositórios públicos do GitHub devem ser exibidos.</p><h4 id="hist-rias-de-usu-rio-1"><strong>Histórias de usuário</strong></h4><ul><li>O usuário pode inserir um nome de usuário do GitHub</li><li>O usuário pode clicar em um botão "Generate" (Gerar) para criar e exibir a linha do tempo do repositório do usuário nomeado</li><li>O usuário poderá ver uma mensagem de aviso se o nome de usuário do GitHub não for válido.</li></ul><h4 id="recursos-adicionais-2"><strong>Recursos adicionais</strong></h4><ul><li>O usuário pode ver um resumo do número de repositórios registrados pelo ano em que foram criados</li></ul><h4 id="links-e-recursos-teis-3"><strong>Links e recursos úteis</strong></h4><p>O GitHub oferece duas APIs que você pode usar para acessar os dados do repositório. Você também pode optar por usar um pacote do NPM para acessar a API do GitHub.</p><p>A documentação da API do GitHub pode ser encontrada em:</p><ul><li><a href="https://developer.github.com/v3/" rel="noopener">GitHub REST API V3</a> (em inglês)</li><li><a href="https://developer.github.com/v4/" rel="noopener">GitHub GraphQL API V4</a> (em inglês)</li></ul><p>O código de exemplo que mostra como usar a API do GitHub é:</p><p>Você pode usar esse comando CURL para ver o JSON retornado pela API REST V3 para seus repositórios:</p><pre><code class="language-bash">curl -u "user-id" https://api.github.com/users/user-id/repos</code></pre><p><strong>Exemplos de projetos</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_FemfK" src="https://codepen.io/NilsWe/embed/preview/FemfK?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=FemfK" title="CSS Timeline" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><figure class="kg-card kg-embed-card"><iframe id="cp_embed_QNeJgR" src="https://codepen.io/tutsplus/embed/preview/QNeJgR?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=QNeJgR" title="Building a Vertical Timeline With CSS and a Touch of JavaScript" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h3 id="14-soletrar"><strong><strong>14. </strong>Soletrar</strong></h3><p><strong>Nível:</strong> 3 - Avançado</p><p><strong>Descrição</strong>: Saber soletrar é parte fundamental para ser fluente em qualquer idioma. Seja você é uma criança aprendendo a soletrar ou um indivíduo aprendendo um novo idioma, a prática ajuda a solidificar suas habilidades linguísticas.</p><p>A aplicação de Soletrar ajuda os usuários a praticar a ortografia reproduzindo a gravação de áudio de uma palavra que o usuário deve soletrar usando o teclado do computador.</p><p><strong>Histórias de usuário</strong></p><ul><li>O usuário pode clicar no botão "Play" (Reproduzir) para ouvir a palavra que deve ser digitada</li><li>O usuário pode ver as letras exibidas na caixa de texto de entrada de palavras à medida que são inseridas no teclado</li><li>O usuário pode clicar no botão "Enter" para enviar a palavra que foi digitada na caixa de texto de entrada de palavras</li><li>O usuário pode ver uma mensagem de confirmação quando a palavra correta é digitada</li><li>O usuário pode ver uma mensagem solicitando que a palavra seja digitada novamente quando ela for escrita incorretamente</li><li>O usuário pode ver um registro do número de grafias corretas, o número total de palavras tentadas e uma porcentagem de entradas bem-sucedidas.</li></ul><h4 id="recursos-adicionais-3"><strong>Recursos adicionais</strong></h4><ul><li>O usuário pode ouvir um som de confirmação quando a palavra for soletrada corretamente</li><li>O usuário pode ouvir um som de aviso quando a palavra for escrita incorretamente</li><li>O usuário pode clicar no botão "Hint" (Dica) para destacar as letras incorretas na caixa de texto de entrada de palavras</li><li>O usuário pode pressionar a tecla "Enter" no teclado para enviar uma palavra digitada ou clicar no botão "Enter" na janela da aplicação</li></ul><p><strong>Links e recursos úteis</strong></p><ul><li><a href="https://en.wikipedia.org/wiki/Speak_%26_Spell_(toy)" rel="noopener">Texas Instruments Speak and Spell</a> (em inglês)</li><li><a href="https://codepen.io/2kool2/full/RgKeyp" rel="noopener">Web Audio API</a> (em inglês)</li><li><a href="https://codepen.io/shangle/full/Wvqqzq">Clique e fale</a> (em inglês)</li></ul><p><strong>Exemplos de projetos</strong></p><p><a href="https://itunes.apple.com/app/id447312716">Assistente de palavras para iOS</a> (em inglês)</p><p><a href="https://play.google.com/store/apps/details?id=au.id.weston.scott.SpeakAndSpell&amp;hl=en_US">Falar e soletrar no Google Play</a> (em inglês)</p><h3 id="15-aplica-o-de-pesquisa"><strong><strong>15</strong>. Aplicação de pesquisa</strong></h3><p><strong>Nível</strong>: 3 - Avançado</p><p><strong>Descrição</strong>: As pesquisas são uma parte valiosa da caixa de ferramentas de qualquer desenvolvedor. Elas são úteis para obter feedback dos usuários sobre uma variedade de tópicos, incluindo satisfação com a aplicação, requisitos, necessidades futuras, problemas, prioridades e incômodos simples, por exemplo.</p><p>A aplicação de pesquisa dá a você a oportunidade de aprender desenvolvendo uma aplicação com todos os recursos que podem ser adicionados à sua caixa de ferramentas. Ela oferece a capacidade de definir uma pesquisa, permitir que os usuários respondam dentro de um período de tempo predefinido e tabular e apresentar resultados.</p><p>Os usuários dessa aplicação são divididos em duas funções distintas, cada uma com requisitos diferentes:</p><ul><li>Os <em>coordenadores de pesquisa</em> definem e conduzem pesquisas. Essa é uma função administrativa não disponível para usuários normais.</li><li><em>Respondentes de pesquisas </em>preenchem pesquisas e visualizam resultados. Eles não têm privilégios administrativos na aplicação.</li><li>As ferramentas de pesquisa comerciais incluem a funcionalidade de distribuição que envia questionários em massa para os Respondentes da pesquisa. Para simplificar, esta aplicação pressupõe que os questionários abertos para respostas serão acessados a partir da página da web da aplicação</li></ul><h4 id="hist-rias-de-usu-rio-2"><strong>Histórias de usuário</strong></h4><h4 id="geral"><strong>Geral</strong></h4><ul><li>Os coordenadores e respondentes de pesquisas podem definir, conduzir e visualizar pesquisas e resultados de pesquisas em um site comum</li><li>Os coordenadores de pesquisa podem fazer login na aplicação para acessar funções administrativas, como definir uma pesquisa.</li></ul><h4 id="defini-o-de-uma-pesquisa"><strong>Definição de uma pesquisa</strong></h4><ul><li>O coordenador de pesquisa pode definir uma pesquisa que contenha de 1 a 10 perguntas de múltipla escolha.</li><li>O coordenador de pesquisa pode definir de 1 a 5 seleções mutuamente exclusivas para cada pergunta.</li><li>O coordenador de pesquisa pode inserir um título para a pesquisa.</li><li>O coordenador de pesquisa pode clicar em um botão "Cancelar" para retornar à página inicial sem salvar o questionário.</li><li>O coordenador do questionário pode clicar em um botão "Salvar" para salvar um questionário.</li></ul><h4 id="realiza-o-de-uma-pesquisa"><strong>Realização de uma pesquisa</strong></h4><ul><li>O coordenador de pesquisa pode abrir uma pesquisa selecionando-a em uma lista de pesquisas previamente definidas</li><li>Os coordenadores de pesquisa podem fechar uma pesquisa selecionando-a em uma lista de pesquisas abertas</li><li>O respondente da pesquisa pode concluir um questionário selecionando-o em uma lista de questionários abertos</li><li>O respondente da pesquisa pode selecionar respostas para as perguntas da pesquisa clicando em uma caixa de seleção</li><li>Os respondentes do questionário podem ver que uma resposta selecionada anteriormente será automaticamente desmarcada se uma resposta diferente for clicada.</li><li>Os respondentes do questionário podem clicar em um botão "Cancelar" para retornar à página inicial sem enviar a pesquisa.</li><li>Os respondentes do questionário podem clicar no botão "Enviar" para enviar suas respostas ao questionário.</li><li>Os respondentes do questionário podem ver uma mensagem de erro se "Enviar" for clicado, mas nem todas as perguntas tiverem sido respondidas.</li></ul><h4 id="visualiza-o-dos-resultados-da-pesquisa"><strong>Visualização dos resultados da pesquisa</strong></h4><ul><li>Os coordenadores e os respondentes de pesquisa podem selecionar a pesquisa a ser exibido em uma lista de questionários fechados</li><li>Os coordenadores e os respondentes da pesquisa podem visualizar os resultados da pesquisa em formato tabular, mostrando o número de respostas para cada uma das seleções possíveis para as perguntas.</li></ul><h4 id="recursos-adicionais-4"><strong>Recursos adicionais</strong></h4><ul><li>Os respondentes da pesquisa podem criar uma conta exclusiva na aplicação</li><li>Os respondentes da pesquisa podem fazer login na aplicação</li><li>Os entrevistados não podem responder à mesma pesquisa mais de uma vez</li><li>Os coordenadores e os respondentes da pesquisa podem visualizar representações gráficas dos resultados da pesquisa (por exemplo, gráficos de pizza, de barras, de colunas etc.)</li></ul><h4 id="links-e-recursos-teis-4"><strong>Links e recursos úteis</strong></h4><p>Bibliotecas para a criação de pesquisas: <a href="https://surveyjs.io/Overview/Library/">SurveyJS</a></p><p>Alguns serviços de pesquisa comercial incluem: <a href="https://www.surveymonkey.com/">Survey Monkey</a> e <a href="https://www.typeform.com/">TypeForm</a></p><p><strong>Exemplo de projeto</strong></p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_oLChg" src="https://codepen.io/amyfu/embed/preview/oLChg?default-tabs=js%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=oLChg" title="Javascript Questionnaire" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h3 id="contribui-o"><em><strong>Contribuição</strong></em></h3><p>Fique à vontade para contribuir com o projeto no <a href="https://github.com/florinpop17/app-ideas">repositório do GitHub</a>! Qualquer contribuição é muito apreciada.</p><p>Você pode contribuir de duas maneiras:</p><ol><li>criar uma <em>issue</em> e nos contar sua ideia. Não se esqueça de usar o rótulo <em>New Idea</em> (<strong>nova ideia</strong>) nesse caso;</li><li>fazer o <em>fork</em> do projeto e enviar um PR. Antes de fazer isso, certifique-se de ler e seguir o Guia de Contribuição (você pode encontrá-lo no repositório);</li></ol><h4 id="adicione-seus-pr-prios-exemplos"><strong>Adicione seus próprios exemplos</strong></h4><p>Você também pode adicionar seus próprios exemplos aos projetos depois de concluí-los. Eu o encorajo a fazer isso, pois mostrará aos outros as coisas incríveis que você construiu!</p><h3 id="espalhe-a-palavra-"><strong>Espalhe a palavra!</strong></h3><p>Se as informações deste artigo e do repositório foram úteis para você de alguma forma, certifique-se de atribuir uma estrela no GitHub. Assim, outras pessoas poderão encontrar o projeto e se beneficiar também! Juntos, podemos crescer e tornar nossa comunidade melhor!</p><p>Você tem alguma sugestão sobre como podemos melhorar este projeto em geral? Entre em contato conosco! Gostaríamos muito de ouvir seus comentários!</p><h4 id="principais-colaboradores"><strong>Principais colaboradores</strong></h4><p><strong><strong>Florin Pop</strong></strong>: <a href="https://twitter.com/florinpop1705" rel="noopener">Twitter</a> e <a href="https://florin-pop.com/">site</a>.</p><p><strong><strong>Jim Medlock</strong></strong>: <a href="https://twitter.com/jd_medlock" rel="noopener">Twitter</a> e <a href="https://medium.com/@jdmedlock" rel="noopener">Medium</a></p><h3 id="desafio-semanal-de-programa-o"><strong>Desafio semanal de programação</strong></h3><p>Como bônus, há um desafio de programação semanal em que você pode aprender mais praticando suas habilidades em projetos do mundo real. Leia o <a href="https://www.florin-pop.com/blog/2019/03/weekly-coding-challenge/">Guia completo</a> (em inglês) para saber como você pode participar!</p><p><em>Publicado originalmente<em> </em>em<em> <a href="https://www.florin-pop.com/blog/2019/03/15-plus-app-ideas-to-build-to-level-up-your-coding-skills/" rel="noopener">www.florin-pop.com</a></em> (texto original em inglês)<em>.</em></em></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como proteger suas conexões WebSocket ]]>
                </title>
                <description>
                    <![CDATA[ A web está crescendo em uma velocidade enorme. As aplicações para a web estão cada vez mais dinâmicas, imersivas e não exigem que o usuário recarregue a página para que ocorram atualizações. O suporte para tecnologias de comunicação de baixa latência como websockets também está em constante evolução. Websockets nos ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-proteger-suas-conexoes-websocket/</link>
                <guid isPermaLink="false">641518ed450cb2052fa76de8</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rafael de Paula Barbosa ]]>
                </dc:creator>
                <pubDate>Thu, 25 May 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/05/1_OO2brLI8iR1wo8bJx7TKOg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-secure-your-websocket-connections-d0be0996c556/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to secure your WebSocket connections</a>
      </p><p>A web está crescendo em uma velocidade enorme. As aplicações para a web estão cada vez mais dinâmicas, imersivas e não exigem que o usuário recarregue a página para que ocorram atualizações. O suporte para tecnologias de comunicação de baixa latência como websockets também está em constante evolução. Websockets nos permitem realizar comunicações em tempo real entre diferentes clients conectados a um mesmo servidor.<br><br>Muitas pessoas não sabem como proteger suas conexões websocket de alguns ataques comuns. Vamos ver quais são eles e o que você pode fazer para deixar seus websockets seguros.</p><h3 id="n-0-habilite-o-cors">Nº 0: Habilite o CORS</h3><p>WebSocket não possui CORS nativo. Isso significa que qualquer site pode se conectar com qualquer outro através de uma conexão websocket sem qualquer restrição! Eu não vou entrar em detalhes acerca dos motivos para que isso seja assim, mas uma maneira rápida de corrigir isso é verificar o cabeçalho de requisição <code>Origin</code> no handshake do WebSocket.<br><br>Claro, o cabeçalho de requisição Origin pode ser falsificado por um invasor, mas não importa, porque, para explorar isso, o invasor precisa falsificar o cabeçalho Origin no navegador da vítima. Navegadores modernos não permitem que códigos convencionais em JavaScript no navegador alterem o cabeçalho Origin.<br><br>Ademais, se você estiver autenticando usuários usando, preferencialmente, cookies, isso não será um problema (mais sobre esse assunto no tópico nº 4).</p><h3 id="n-1-implementando-taxa-de-limita-o">Nº 1: Implementando taxa de limitação</h3><p>A taxa de limitação é importante. Sem ela, <em>clients</em> podem – cientes ou não – realizar um ataque do tipo DoS (Denial of Service) no seu servidor. Em outras palavras, DoS significa que um único <em>client</em> está fazendo com que o servidor fique ocupado a ponto de não conseguir lidar com com outros <em>clients</em>.</p><p>Na maioria dos casos, é uma tentativa deliberada vinda de um invasor visando derrubar o servidor. Às vezes, uma implementação ruim no front-end também pode gerar um ataque DoS por <em>clients</em> normais.</p><p>Faremos uso do algoritmo do balde furado (em inglês, <em>leaky bucket</em> – o qual, aparentemente, é um algoritmo muito usado para implementação de redes) para implementar a taxa de limitação em nossos <em>websockets</em>.</p><p>A ideia é que você tenha um balde com um furo de tamanho fixo no fundo. Você começa colocando água nele e a água sai pelo buraco no fundo. Agora, se o balde receber mais água do que está sendo escoado por um longo período de tempo, em algum momento o balde ficará cheio e começará a vazar. É isso.</p><p>Agora, vamos entender como isso tem relação com nosso <em>websocket</em>:</p><p>A água é o tráfego do <em>websocket </em>enviado pelo usuário.</p><p>A água passa pelo buraco no fundo do balde. Isso significa que o servidor processou aquela requisição em particular com sucesso.</p><p>A água que está no balde e ainda não vazou é basicamente o tráfego pendente. O servidor processará esse tráfego depois. Isso pode ser também um tráfego em massa, ou seja, muito tráfego de uma vez só, contanto que o balde não vaze).</p><p>A água que está vazando é o tráfego descartado pelo servidor (muito tráfego proveniente de um único usuário).</p><p>O ponto aqui é que você tem que verificar a atividade do seu <em>websocket </em>e determinar esses números. Você estabelecerá um balde para cada usuário. Decidiremos o tamanho que o balde deve ter (tráfego o qual um único usuário poderá enviar durante o período específico) dependendo do tamanho do buraco ao fundo do balde (quanto tempo em média o seu servidor leva para processar uma única requisição <em>websocket</em>, digamos que salvando uma mensagem enviada pelo usuário em um banco de dados, por exemplo).</p><p>Essa é uma implementação simples que eu estou usando no <a href="https://codedamn.com/">codedamn</a> para implementar o algoritmo de balde furado para <em>websockets</em>. É em NodeJS, mas os conceitos são sempre os mesmos.</p><pre><code>if(this.limitCounter &gt;= Socket.limit) {
  if(this.burstCounter &gt;= Socket.burst) {
     return 'O balde está vazando'
  }
  ++this.burstCounter
  return setTimeout(() =&gt; {
  this.verify(callingMethod, ...args)
  setTimeout(_ =&gt; --this.burstCounter, Socket.burstTime)
  }, Socket.burstDelay)
}
++this.limitCounter</code></pre><p>Então, o que está acontecendo aqui? Basicamente, se o limite for alcançado tanto pelo limite de tráfego (que são constantes definidas), a conexão <em>websocket </em>cai. Caso contrário, após um certo tempo, resetaremos o contador de tráfego. Isso deixa espaço livre para outro tráfego em massa.</p><h3 id="n-2-restrinja-o-tamanho-da-carga">Nº 2: Restrinja o tamanho da carga</h3><p>Isso deve ser utilizado como um recurso do seu <em>framework </em>de <em>back-end</em>. Se o seu não tem, é hora de mudar para um melhor! Você deve limitar o tamanho máximo da mensagem que será enviada pelo seu <em>websocket</em>. Teoricamente, não há limite. Claro, é bem provável que receber uma carga muito grande congestionará essa instância de <em>websocket </em>específica e consumirá mais recursos do sistema do que deveria.</p><p>Por exemplo, se você está usando a biblioteca WS para Node para criar <em>websockets </em>no servidor, você pode usar a <a href="https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback">opção maxPayload</a> para especificar o tamanho máximo da carga em bytes. Se o tamanho da carga for maior que o definido, a biblioteca, nativamente, derrubará a conexão.</p><p>Não tente implementar isso por conta própria determinando o tamanho da mensagem. Não queremos ler a mensagem inteira na memória RAM do sistema. Se a mensagem for 1 byte acima do limite, descarte-a. Isso pode ser implementado pelo <em>framework </em>(que lidará com as mensagens como fluxo de bytes em vez de strings fixas).</p><h3 id="n-3-crie-um-protocolo-de-comunica-o-s-lido">Nº 3: Crie um protocolo de comunicação sólido</h3><p>Como agora você está em uma conexão duplex, você pode enviar qualquer coisa para o servidor. O servidor também pode enviar qualquer texto de volta para o <em>client</em>. Você pode precisar de um caminho para assegurar a comunicação efetiva entre os dois.</p><p>Você não pode enviar mensagens brutas se quiser escalar o aspecto das mensagens do seu site. Eu prefiro usar JSON, mas existem outros meios optimizados de configurar a comunicação. No entanto, considerando o JSON, é assim que um esquema básico de mensagens deve parecer em um site genérico:</p><p>Do <em>client </em>para o servidor (ou vice-versa):</p><pre><code>{ status: "ok"|"error", event: EVENT_NAME, data: &lt;dados de qualquer tipo&gt; }</code></pre><p>Agora, fica mais fácil para você validar eventos e formatos no <em>back-end</em>. Derrube a conexão imediatamente e registre o endereço de IP do usuário, caso o formato da mensagem for diferente. De modo algum o formato pode mudar, a menos que alguém esteja manualmente mexendo na sua conexão <em>websocket</em>. Se você está utilizando o Node, eu recomendo usar a <a href="https://github.com/hapijs/joi">biblioteca Joi</a> para as próximas validações de dados provenientes do usuário.</p><h3 id="n-4-autentique-os-usu-rios-antes-de-estabilizar-a-conex-o-ws">Nº 4: Autentique os usuários antes de estabilizar a conexão WS</h3><p>Se você está utilizando <em>websockets </em>para usuários autenticados, é uma ótima ideia permitir que apenas usuários autenticados estabeleçam com sucesso uma conexão <em>websocket</em>. Não permita que ninguém estabeleça uma conexão e espere que eles se autentiquem no próprio <em>websocket</em>. Primeiramente, estabelecer uma conexão <em>websocket </em>é sempre um pouco caro. Logo, você não quer que pessoas sem autorização acessem seu <em>websocket</em> e monopolizem as conexões que poderiam ser utilizadas por outras pessoas.</p><p>Para isso, quando estiver estabelecendo uma conexão no <em>front-end</em>, envie algum dado de autenticação para o <em>websocket</em>. Pode ser um header como <code>X-Auth-Token: &lt;token atribuído a este client no login&gt;</code>. Por padrão, <em>cookies </em>serão passados de qualquer jeito.</p><p>De novo, realmente depende da biblioteca que você está utilizando para implementar <em>websockets</em>. Se, contudo, você estiver usando Node e a WS, existe uma função chamada <a href="https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback">verifyClient</a> que te dá acesso às informações do objeto passado pela conexão <em>websocket</em> (assim como você tem acesso ao objeto req para solicitações HTTP).</p><h3 id="n-5-use-ssl-com-websockets">Nº 5: Use SSL com websockets</h3><p>Isso não é trivial, mas é necessário ser dito. Use wws:// em vez de ws://. Isso adiciona uma camada de segurança à sua conexão. Use um servidor como o Nginx para realizar proxy reverso nos <em>websockets</em> e habilitar SSL acima deles. Como configurar o Nginx será um tutorial à parte, eu vou deixar algumas diretivas que você precisa utilizar no Nginx para as pessoas que são familiarizadas com ele. <a href="http://nginx.org/en/docs/http/websocket.html">Mais informações aqui</a>.</p><pre><code>location /local-do-seu-websocket/ {
    proxy_pass ​http://127.0.0.1:1337;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
}</code></pre><p>Aqui, assumimos que o seu servidor <em>websocket </em>está ouvindo na porta 1337 e que seus usuários estão conectados ao seu <em>websocket </em>assim:</p><pre><code>const ws = new WebSocket('wss://seusite.com/local-do-seu-websocket')</code></pre><p>Obrigado pela leitura!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ O que é um Developer Advocate? ]]>
                </title>
                <description>
                    <![CDATA[ Versão resumida: é o melhor amigo do desenvolvedor! Escrito por: Wassim Chegham Nos últimos três anos, eu tenho dedicado meu tempo profissional e uma grande parte do meu tempo pessoal para ajudar outros desenvolvedores a serem bem-sucedidos e produtivos com as ferramentas que eles amam e usam. Essas ferramentas incluem ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/o-que-e-um-developer-advocate/</link>
                <guid isPermaLink="false">63c901f891baea05fef70e2b</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fabiana Prestes Goncalves ]]>
                </dc:creator>
                <pubDate>Wed, 05 Apr 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/04/1_cy4abxRJrbqcxLq_-4uVCw.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/what-the-heck-is-a-developer-advocate-87ab4faccfc4/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">What the heck is a Developer Advocate?</a>
      </p><h3 id="vers-o-resumida-o-melhor-amigo-do-desenvolvedor-">Versão resumida: é o melhor amigo do desenvolvedor!</h3><p>Escrito por: Wassim Chegham</p><p>Nos últimos três anos, eu tenho dedicado meu tempo profissional e uma grande parte do meu tempo pessoal para ajudar outros desenvolvedores a serem bem-sucedidos e produtivos com as ferramentas que eles amam e usam. Essas ferramentas incluem plataformas da web, tais como JavaScript, PWA e Angular, Google Cloud Platform, Actions no Google e chatbots em geral. É isso que eu faço como um Developer Advocate.</p><p>Este artigo é baseado na minha experiência pessoal como Developer Advocate. Fala de coisas que aprendi pessoalmente, mas também do que aprendi com outros Developer Advocates e nas empresas com as quais eu trabalhei.</p><h3 id="minha-hist-ria-"><strong><strong><strong>M</strong>inha história<strong>…</strong></strong></strong></h3><p>Há treze anos, quando eu estava estudando eletrônica e depois ciência da computação na universidade, nos ensinaram toda a teoria de paradigmas da computação e programação, estruturas de dados, padrões de projetos, compiladores, linguagens e assim por diante. Basicamente, nos ensinaram tudo o que engenheiros de software júnior precisam saber para começar suas carreiras.</p><p>Entretanto, eu estava provavelmente muito interessado no curso, porque eu sempre fazia mais do que era pedido nos trabalhos de classe. O que quero dizer é que aprender Java na universidade era interessante, mas eu estava ficando entediado. Eu passava a maior parte do meu tempo livre aprendendo novos paradigmas de programação de linguagens como Python, PHP, Assembly 8086, oCaml e JavaScript. Foi quando eu descobri e me apaixonei por JavaScript e decidi, desde então, sempre apostar em JavaScript. Nunca me arrependi de ter feito isso.</p><p>Eu tive que aprender novas linguagens construindo ferramentas, scripts, aplicações, qualquer coisa que me ajudasse a entender o funcionamento interno da linguagem – indo muito além da sintaxe. Claro, eu ainda era um estudante nessa época e estava tentando entender como as coisas funcionavam e como solucionar todos os bugs que eu estava criando.</p><p>Então, apareceu a comunidade de desenvolvedores. Graças a web, eu pude pedir e receber ajuda de outros seres humanos – uma comunidade de desenvolvedores professionais e experientes. Eu estava admirado! Eu estava aprendendo muito com os outros desenvolvedores, lendo seus insights nas postagens em blogs, assistindo aos tutoriais no YouTube e discutindo diferentes tópicos em diferentes fóruns de tecnologia e IRC (sim, ele ainda existe!) </p><p>Aprendi muito com o que outros desenvolvedores compartilhavam gratuitamente, apenas para ajudar os outros. Por isso, decidi unir-me a comunidade e fazer o meu melhor para compartilhar o que eu estava aprendendo. Para mim, essa era a coisa certa a se fazer: outras pessoas ajudaram a me tornar um bom desenvolvedor. Agora, era minha vez de retribuir e ajudar outros desenvolvedores. Foi então que eu comecei a me preocupar com a produtividade dos outros desenvolvedores e com a minha também, claro. Estamos todos no mesmo barco, certo?</p><p>À medida que eu estava crescendo profissionalmente, comecei a pensar em novas maneiras de ajudar meus colegas desenvolvedores. Escrever artigos (no Medium e em revistas impressas) foi um grande começo, mas eu não conseguia medir o impacto que minhas publicações estavam tendo no público-alvo. Decidi, então, sair e conhecer esses desenvolvedores. Eu esperava não só compartilhar com eles, mas também apreender com eles na vida real. Como já era de se esperar, encontros, conferências e eventos para desenvolvedores são onde você pode encontrar todos esses desenvolvedores apaixonados. </p><blockquote>Além disso: ser apaixonado por ajudar outros desenvolvedores pode (com sorte) também fazer com que você seja nomeado para o programa <a href="https://developers.google.com/experts/people/wassim-chegham" rel="noopener">Google Developer Experts</a> (ou para outros programas similares). Tive muita sorte em ingressar no programa do GDE há três anos e poder ajudar e influenciar ainda mais colegas desenvolvedores! Obrigado, Google!</blockquote><h3 id="resumindo-"><strong>Resumindo<strong><strong>…</strong></strong></strong></h3><p>Eu continuo aqui, ainda gostando de ajudar meus colegas desenvolvedores. Acreditem ou não, esse se tornou meu trabalho em tempo integral na SFEIR como Developer Advocate sênior.</p><p>Então, o que é um Developer Advocate? O que é necessário para ser um bom Developer Advocate? Por que contratar Developer Advocates dedicados/apaixonados é a decisão certa a ser tomada como empresa? Vou tentar responder a essas perguntas.</p><h4 id="o-que-um-developer-advocate"><strong>O que é um <strong><strong>Developer Advocate?</strong></strong></strong></h4><p>Em primeiro lugar, vamos deixar claro para todos: Developer Advocates também são engenheiros. Eles têm um forte histórico técnico em seus campos, criaram e enviaram aplicações para a produção. Alguns deles, inclusive, causaram <em>crashes </em>na produção ou excluíram acidentalmente banco de dados de clientes (isso aconteceu, de verdade)!</p><p>De acordo com esse requisito, Developer Advocates não deveriam ser pessoas da área de marketing ou vendas – há funções mais adequadas para essas pessoas. Porém, Developer Advocates deveriam ser capazes de dar feedback para as áreas de marketing ou vendas. Mais importante — pelo menos, para mim — é dar feedback ao gerenciamento de produto, influenciar no roteiro de criação do produtos com base, é claro, nas necessidades dos desenvolvedores. </p><p>Historicamente, muitas empresas em tecnologia contrataram Developer Advocates para defender suas plataformas, ajudando desenvolvedores a usar seus produtos – e eles ainda o fazem. Portanto, a função de um Developer Advocate é <strong>ajudar os desenvolvedores a terem sucesso com uma plataforma ou tecnologia</strong>. O papel de um Developer Advocate também é atuar como uma ponte entre o time de engenharia e a comunidade de desenvolvedores. <strong>A função deles é dar<strong> feedback </strong>a ambas as partes, igualmente,<strong> </strong>em ambos os sentidos.</strong></p><blockquote><strong>Um <strong>Developer Advocate </strong>é alguém que realmente defende os <strong>de</strong>senvolvedores<strong>, </strong>não somente uma plataforma<strong>. </strong>Os d<strong>e</strong>senvolvedores deveriam ser a prioridade dos<strong> Developer Advocate</strong>s<strong>.</strong></strong></blockquote><h4 id="o-que-necess-rio-para-ser-um-bom-developer-advocate"><strong>O que é necessário para ser um bom<strong><strong> Developer Advocate?</strong></strong></strong></h4><p>Acredito que engenheiros não se tornam Developer Advocates porque seus gerentes pedem. Também acredito que Developer Advocates são pessoas inerentemente apaixonadas e altruístas. Essas características não podem ser simplesmente ensinadas ou aprendidas. </p><p>Pessoalmente, tentei convencer alguns desenvolvedores a começar a compartilhar o conhecimento deles, mas eu estava errado! Descobri que alguns engenheiros se sentem mais confortavéis programando (quem não se sentiria?) e dedicando-se totalmente a resolver problemas ou desenvolver produtos. Compartilhar conhecimento com outros desenvolvedores nã0 é a principal prioridade de todos os engenheiros. Isso é totalmente normal e deve ser respeitado. Se você é um gerente, não obrigue seus engenheiros a fingir ser o que eles não são e não os coloque em situações desconfortáveis. Ninguém quer estar nessa situação.</p><p>Então o que é necessário para ser um bom Developer Advocate? Aprendi que muitos, se não todos os Developer Advocates, têm as seguintes características.</p><p><strong>Aprender c<strong>ont</strong>inuamente<strong> </strong></strong></p><p>Como engenheiros, nunca paramos de aprender, mesmo depois de terminar a universidade. Sem dúvida, o verdadeiro conhecimento está por aí para ser descoberto. Developer Advocates, como qualquer outro engenheiro, são pessoas que gostam de aprender. Eles procuram conhecimento em todos os lugares. Usam todos os meios que conhecem para se manterem atualizados. Os Developer Advocates que eu conheço defendem uma plataforma ou produto, mas também experimentam e usam outros produtos – até mesmo os feitos pelos seus competidores. Por quê? Porque os desenvolvedores geralmente necessitam usar diferentes produtos e ferramentas para construir suas aplicações. Um Developer Advocate sabe disso!</p><p><strong>Pensar fora da caixa</strong></p><p>Aprender coisas novas não vale a pena se você não as questiona. Eu nunca considero algo que acabei de aprender como certo. Eu sempre me faço as mesmas perguntas: "Por que …?", "E se …?", "Como esse recurso pode ser melhorado?", "Qual é a aparência disso internamente?" Claro que qualquer engenheiro curioso naturalmente faria essas perguntas.</p><p>Developer Advocates não são exceções. Eles devem ser capazes de dar uma explicação de alto nível sobre como um recurso funciona internamente ou simplesmente fornecer algumas informações técnicas sobre o produto ou plataforma que eles defendem. Muitos desenvolvedores perguntarão sobre isso mais cedo ou mais tarde e você precisa estar preparado.</p><p><strong>Criar aplicações para o mundo real </strong></p><p>Aprender novas coisas e saber a teoria por detrás delas não vale a pena se você não criar aplicações que as utilizem. Se você vai defender desenvolvedores, o mínimo que você pode fazer é colocar-se no lugar do desenvolvedor tentando dominar o produto e a plataforma que você está defendendo. Esse é o momento no qual suas habilidades de engenharia serão úteis. </p><p>Criar aplicações reais com as ferramentas que você defende ajudará você a entender melhor quais são suas limitações e, com sorte, a sugerir algumas melhorias ao time de engenharia. A função de um Developer Advocate é também garantir que a plataforma e as ferramentas que você defende forneçam a melhor experiência para o desenvolvedor.</p><p><strong>Compartilhar e preocupar-se</strong></p><p>A habilidade de "compartilhar" informações com a comunidade de desenvolvedores é uma parte essencial na função desempenhada pelo Developer Advocate. Você não pode desenvolver essa função se não gosta de compartilhar ou ajudar a outras pessoas. Tudo bem: nem todos somos altruístas! Porém, fingir que está defendendo desenvolvedores será muito — e não me canso de dizer — muito desafiador!</p><p>Além disso, a maioria das empresas exige, nos seus anúncios de emprego, para a função de Developer Advocate, uma boa habilidade de comunicação oral e escrita. Embora eu concorde com esse requisito, também acredito que "habilidades de comunicação" não deveriam substituir nem serem confundidas com as habilidades de "compartilhar e se preocupar". Reformulando, contratar um Developer Advocate que realmente ama compartilhar e ajudar a outras pessoas é mais importante do que contratar alguém com uma boa habilidade de comunicação. Na verdade, o primeiro é mais difícil de desenvolver!</p><p>Então, resumindo: você quer contratar um bom Developer Advocate? Contrate um aprendiz curioso e ávido, que tenha a mente aberta, com boas habilidades de engenharia e habilidades genuínas de "compartilhamento e empatia".</p><p>Você pode mandar uma mensagem para o autor pelo <a href="https://twitter.com/manekinekko">Twitter</a> caso tenha gostado do artigo e segui-lo caso queira ler mais sobre conteúdos semelhantes. Obrigado pela leitura!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como pensar como um programador — lições de resolução de problemas ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Richard Reis > Tradução em português europeu Se tens interesse em programação, é possível que já tenhas visto esta citação: > "Toda a gente neste país deve aprender a programar um computador, porque ensina-te a pensar." — Steve Jobs Também te deves ter questionado sobre o que é, ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-pensar-como-um-programador-licoes-de-resolucao-de-problemas/</link>
                <guid isPermaLink="false">63a579186389b20662b615da</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Afonso Branco ]]>
                </dc:creator>
                <pubDate>Wed, 08 Feb 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_HTRqXgr7CVtRBsyTxurQew.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-think-like-a-programmer-lessons-in-problem-solving-d1d8bf1de7d2/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to think like a programmer — lessons in problem solving</a>
      </p><p>Escrito por: Richard Reis</p><blockquote>Tradução em português europeu</blockquote><p>Se tens interesse em programação, é possível que já tenhas visto esta citação:</p><blockquote>"Toda a gente neste país deve aprender a programar um computador, porque ensina-te a pensar." — Steve Jobs</blockquote><p>Também te deves ter questionado sobre o que é, exatamente, pensar como um programador e sobre <em>como</em> podes fazê-lo.</p><p>Essencialmente,<strong><strong><em><em> </em></em></strong></strong>trata-se de <strong>um modo mais eficiente de resolver problemas</strong>.</p><p>Nesta publicação, o meu objetivo é ensinar-te esse modo.</p><p>No final da publicação, ficarás a saber exatamente quais os passos a dar para ser um(a) melhor solucionador(a) de problemas.</p><h4 id="qual-a-import-ncia-disso"><strong>Qual é a importância disso?</strong></h4><p>A resolução de problemas é a habilidade das habilidades.</p><p>Todos temos problemas. Grandes e pequenos. O modo como lidamos com eles é, por vezes, bem… bastante aleatório.</p><p>A não ser que tenhas um sistema, esta é a forma como provavelmente "resolves" os problemas (que é o que eu fazia quando comecei a programar):</p><ol><li>Tentar uma solução.</li><li>Se não funcionar, tentar outra.</li><li>Se também não funcionar, repetir o passo 2 até teres sorte.</li></ol><p>Vejamos: por vezes, podes ter sorte. Esse, porém, é o pior modo de resolver problemas, além de ser um enorme desperdício de tempo.</p><p>A melhor forma envolve a) ter uma estrutura e b)<strong><strong> p</strong>raticá-la<strong>.</strong></strong></p><blockquote>"Quase todos os empregadores dão prioridade a competências de resolução de problemas. <br><br>A resolução de problemas é, de maneira quase unânime, a qualificação mais importante procurada pelos empregadores… mais do que proficiência em linguagens de programação, depuração e design de sistemas. <br><br>Demonstrar pensamento computacional ou a capacidade de decompor problemas grandes e complexos é tão valioso (se não mais) como as competências técnicas necessárias para a vaga." — Hacker Rank (<a href="https://research.hackerrank.com/developer-skills/2018/" rel="noopener">2018 Relatório de Competências do Programador</a>)</blockquote><h4 id="ter-uma-estrutura"><strong>Ter uma estrutura</strong></h4><p>Para encontrar a estrutura certa, segui o conselho no livro de Timothy Ferriss, "<a href="https://www.amazon.com.br/4-Hour-Chef-Cooking-Learning-Anything/dp/1328519163/ref=sr_1_7?keywords=timothy+ferriss&amp;qid=1675305200&amp;sprefix=Timothy+ferr%2Caps%2C264&amp;sr=8-7&amp;ufe=app_do%3Aamzn1.fos.4bb5663b-6f7d-4772-84fa-7c7f565ec65b">The 4-Hour Chef</a>".</p><p>Levou-me a entrevistar duas pessoas muito interessantes: <a href="https://www.linkedin.com/in/cjordanball/" rel="noopener">C. Jordan Ball</a> (classificado em primeiro ou segundo em mais de 65 mil utilizadores no <a href="https://coderbyte.com/" rel="noopener">Coderbyte</a>) e <a href="http://vantonspraul.com/" rel="noopener">V. Anton Spraul</a> (autor do livro "<a href="https://www.amazon.com.br/Think-Like-Programmer-Introduction-Creative/dp/1593274246/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=1KI0YRH3IAPPN&amp;keywords=anton+spraul&amp;qid=1675305381&amp;sprefix=anton+spraul%2Caps%2C238&amp;sr=8-1&amp;ufe=app_do%3Aamzn1.fos.6121c6c4-c969-43ae-92f7-cc248fc6181d">Think Like a Programmer: An Introduction to Creative Problem Solving</a>").</p><p>Fiz-lhes algumas perguntas, e adivinha? As respostas de ambos foram bastante semelhantes!</p><p>Brevemente, também vais sabê-las.</p><p>Nota: isto não significa que fizeram tudo do mesmo modo. Toda a gente é diferente. Tu serás diferente. Se, no entanto, começares com princípios que todos concordamos que são bons, vais muito mais longe e mais rápido.</p><blockquote>"O maior erro que vejo novos programadores a fazer é focarem-se em aprender a sintaxe em vez de aprender como resolver problemas." —<a href="http://vantonspraul.com/" rel="noopener"> V. Anton Spraul</a></blockquote><p>Então, o que deves fazer quando te deparas com um novo problema?</p><p>Aqui estão os passos:</p><h4 id="1-compreender"><strong>1. Compreender</strong></h4><p>Saber exatamente o que está a ser perguntado. A maioria dos problemas difíceis são difíceis porque não os compreendes (e por isso é que este é o primeiro passo).</p><p>Como saber quando compreendes um problema? Quando o conseguires explicar por palavras tuas.</p><p>Lembras-te de estar preso num problema, começas a explicá-lo e reparas, instantaneamente, em problemas na lógica que ainda não tinhas reparado?</p><p>A maioria dos programadores conhece essa sensação.</p><p>É por isso que devemos escrever o nosso problema, rabiscar um diagrama, ou falar com alguém sobre ele (ou alguma coisa… há quem utilize um <a href="https://pt.wikipedia.org/wiki/Debug_com_Pato_de_Borracha">pato de borracha</a>).</p><blockquote>"Se não conseguires explicar alguma coisa em termos simples, não a compreendes." — Richard Feynman</blockquote><h4 id="2-planificar"><strong>2. Planificar</strong></h4><p>Não avances logo para a resolução sem teres um plano (e esperar que por acaso consigas desenrascar-te pelo caminho). Planifica a tua solução!</p><p>Nada te pode ajudar se não conseguires escrever os passos exatos.</p><p>Em programação, isso quer dizer que não começas logo a resolver. Dá tempo ao teu cérebro para analisar o problema e processar a informação.</p><p>Para obter um bom plano, responde a esta questão:</p><p>"Dado um valor de entrada X, quais são os passos necessários para obter o resultado Y?"</p><p>Nota: os programadores têm uma ótima ferramenta para ajudá-los com isto… Comentários!</p><h4 id="3-dividir"><strong>3. Dividir</strong></h4><p>Presta atenção. Este é o passo mais importante de todos.</p><p>Não tentes resolver um grande problema. Vais arrepender-te.</p><p>Em vez disso, divide o problema em problemas mais pequenos. Esses problemas são muito mais fáceis de resolver.</p><p>Depois, resolve cada sub-problema, um de cada vez. Começa pelo mais simples. Mais simples significa que sabes a resposta (ou estás perto de saber a resposta).</p><p>Depois disso, o mais simples significa que este sub-problema a ser resolvido não depende da resolução de outros.</p><p>Assim que resolveres todos os sub-problemas, junta os pontos.</p><p>Conectar todas as tuas <em>"<em>sub</em>-<em>solu</em>ções"</em> vai dar-te a solução para o problema original. Parabéns!</p><p>Esta técnica é o pilar da resolução de problemas. Memoriza-a (relê este passo, caso necessário).</p><blockquote>"Se conseguisses ensinar a todos os programadores principiantes uma habilidade de resolução de problemas, esta deveria ser a 'técnica de redução do problema'. <br>Por exemplo, vamos supor que és um novo programador e pedem-te para escrever um programa que lê dez números e tenta perceber qual deles é o terceiro maior. Para um novo programador, esta pode ser uma tarefa complicada, apesar de ser necessária apenas sintaxe de programação básica. <br>Se estiveres preso, deves reduzir o problema para algo mais simples. Em vez do terceiro maior número, por que não encontrar o maior de todos? Ainda muito complicado? Que tal encontrar o maior de apenas três números? Ou o maior de dois? <br>Reduz o problema até ao ponto em que sabes como resolvê-lo e escreve a solução. Depois, expande ligeiramente o problema e escreve de novo uma solução correspondente, continuando assim até chegares ao ponto inicial." — <a href="http://vantonspraul.com/" rel="noopener">V. Anton Spraul</a></blockquote><h4 id="4-sem-saber-o-que-fazer"><strong>4. Sem saber o que fazer?</strong></h4><p>Neste momento, deves estar a pensar "Ei, Richard... isso é muito bonito, mas e se eu não souber o que fazer nem conseguir resolver um sub-problema?"</p><p>Em primeiro lugar, respira fundo. Em segundo, é justo.</p><p>No entanto, não te preocupes. Isto acontece a todos!</p><p>A diferença é que os melhores programadores/solucionadores de problemas ficam mais curiosos com bugs/erros do que irritados.</p><p>Na verdade, aqui estão três coisas para tentares fazer quando te deparares com um obstáculo:</p><ul><li>Debug: vai passo a passo pela tua solução e tenta encontrar onde ocorreu o erro. Os programadores chamam a isto de <em><em>debugging </em></em>(na verdade, isto é tudo o que um <em>debugger</em> faz).</li></ul><blockquote>"A arte do debugging é compreender o que realmente indicaste ao teu programa para fazer e não o que pensas que mandaste fazer." — Andrew Singer</blockquote><ul><li>Reavaliar:<strong><strong> </strong></strong>Dá um passo atrás. Olha para o problema a partir de uma nova perspetiva. Existe alguma coisa que possa ser substituída por uma abordagem mais genérica?</li></ul><blockquote>"Por vezes, ficamos tão perdidos nos detalhes de um problema que ignoramos os princípios gerais que resolveriam o problema num nível mais genérico. […]</blockquote><blockquote>Um exemplo clássico disso é, claro, a soma de uma longa lista de números inteiros consecutivos, 1 + 2 + 3 + … + n, onde um Gauss muito jovem rapidamente reconheceu que era simplesmente n(n+1)/2, evitando assim o trabalho de ter de fazer a adição." — <a href="https://www.linkedin.com/in/cjordanball/" rel="noopener">C. Jordan Ball</a></blockquote><p>Nota: outro modo de reavaliar é começar de novo. Apaga tudo e começa de novo com a cabeça fresca. Estou a falar a sério. Vais ficar estupefacto com a eficácia disto.</p><ul><li>Pesquisa:<strong><strong> </strong></strong>ahh, o velho amigo Google. Leste bem. Não interessa qual é o teu problema. Ele, provavelmente, já foi resolvido por alguém. Encontra essa pessoa/solução. Na verdade, faz isto mesmo que tenhas resolvido o problema! Podes aprender muito com as soluções de outras pessoas.</li></ul><p>Atenção: não procures pela solução de um grande problema. Procura apenas soluções para os sub-problemas. Por quê? Porque a não ser que tenhas dificuldades (mesmo que poucas), não vais aprender nada. Se não aprenderes nada, desperdiçaste o teu tempo.</p><h4 id="praticar"><strong>Praticar</strong></h4><p>Não fiques à espera de ser o(a) melhor ao fim de apenas uma semana. Se quiseres ser bom a resolver problemas, resolve muitos problemas!</p><p>Pratica. Pratica. Pratica. Será apenas uma questão de tempo até reconheceres que "este problema era facilmente resolvido com &lt;inserir conceito aqui&gt;".</p><p>Como praticar? Existem opções até dizer chega!</p><p>Puzzles de xadrez, problemas matemáticos, Sudoku, Go, Monopoly, jogos, e assim por diante.</p><p>Na realidade, um padrão comum entre pessoas bem sucedidas é o seu hábito de praticar "micro-resolução de problemas". Por exemplo, Peter Thiel joga xadrez e Elon Musk joga jogos.</p><blockquote>"Byron Reeves disse que 'Se quiseres ver como se parecerá a liderança das empresas em três a cinco anos, observa o que está a acontecer nos jogos online.'</blockquote><blockquote>Avançamos até hoje. Elon [Musk], Reid [Hoffman], Mark Zuckerberg e muitos outros dizem que os jogos foram fundamentais no seu sucesso em criar as suas empresas." — Mary Meeker (<a href="https://www.recode.net/2017/5/31/15693686/mary-meeker-kleiner-perkins-kpcb-slides-internet-trends-code-2017" rel="noopener">2017 – Relatório de tendências na internet</a>)</blockquote><p>Isto quer dizer que devo dedicar-me apenas a jogar? Nem por isso.</p><p>O que são os jogos, contudo? É isso mesmo: resolução de problemas!</p><p>Então, o que deves fazer é encontrar um canal para praticar. Algo que te permita resolver muitos micro-problemas (idealmente, algo que gostes).</p><p>Por exemplo, eu gosto de desafios de programação. Todos os dias, tento resolver pelo menos um desafio (geralmente no <a href="https://coderbyte.com/" rel="noopener">Coderbyte</a>).</p><p>Tal como disse, todos os problemas partilham padrões semelhantes.</p><h4 id="conclus-o"><strong>Conclusão</strong></h4><p>É isto!</p><p>Agora, compreendes melhor o que significa "pensar como um programador".</p><p>Também sabes que a resolução de problemas é uma habilidade incrível para cultivar (a habilidade das habilidades).</p><p>Como se isto não fosse suficiente, repara como também sabes o que tens de fazer para praticar as tuas habilidades de resolução de problemas!</p><p><em>Ufa<em>…</em></em> Muito interessante, certo?</p><p>Por fim, desejo que encontres muito problemas.</p><p>Leste bem. Pelo menos, agora saberás como resolvê-los! Além disso, vais aprender que, com cada solução, estás a evoluir.</p><blockquote>"Assim que achares que navegaste um obstáculo com sucesso, outro emerge. Isso, porém, é o que torna a vida interessante.[…] <br>A vida é o processo de lidar com todos estes impedimentos — uma série de linhas fortificadas que temos de ultrapassar. <br>De cada vez, vais aprender alguma coisa. <br>De cada vez, vais desenvolver força, sabedoria e perspetiva. <br>De cada vez, um pouco mais de competição fica para trás. Até que tudo o que resta és tu: a melhor versão de ti próprio." — Ryan Holiday (<a href="https://www.amazon.com.br/obst%C3%A1culo-caminho-transformar-prova%C3%A7%C3%B5es-triunfo/dp/6555604085/ref=sr_1_1?keywords=o+obstaculo+e+o+caminho+ryan+holiday&amp;qid=1675306238&amp;sprefix=ryan+h%2Caps%2C289&amp;sr=8-1">O obstáculo é o caminho</a>)</blockquote><p>Agora, é hora de começar a resolver problemas!</p><p>Boa sorte!</p><p><strong>Agradecimentos especiais</strong> a <a href="https://www.linkedin.com/in/cjordanball/" rel="noopener">C. Jordan Ball</a> e <a href="http://vantonspraul.com/" rel="noopener">V. Anton Spraul</a>. Todos os bons conselhos vieram deles.</p><p>Obrigado pela leitura! Se gostaste, compartilha este artigo com quem quiseres. Isso vai ajudar outras pessoas a verem a história.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tudo o que você precisa saber sobre estruturas de dados em árvore ]]>
                </title>
                <description>
                    <![CDATA[ Quando você aprende a programar pela primeira vez, é comum aprender arrays como a "principal estrutura de dados". Em algum momento, você também aprenderá sobre tabelas hash. Se você estiver buscando o diploma em Ciência da Computação, você terá que fazer uma disciplina de estrutura de dados. Você também aprenderá ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/tudo-o-que-voce-precisa-saber-sobre-estruturas-de-dados-em-arvore/</link>
                <guid isPermaLink="false">6354ed2b191d0905ea419365</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Sun, 18 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_WeWOBZy6N7cXkq4inS7FVA.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/all-you-need-to-know-about-tree-data-structures-bceacb85490c/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Everything you need to know about tree data structures</a>
      </p><h3 id="quando-voc-aprende-a-programar-pela-primeira-vez-comum-aprender-arrays-como-a-principal-estrutura-de-dados-">Quando você aprende a programar pela primeira vez, é comum aprender arrays como a "principal estrutura de dados".</h3><p>Em algum momento, você também aprenderá sobre tabelas <code>hash</code>. Se você estiver buscando o diploma em Ciência da Computação, você terá que fazer uma disciplina de estrutura de dados. Você também aprenderá sobre <code>listas vinculadas</code>, <code>filas</code> e <code>pilhas</code>. Essas estruturas de dados são chamadas de estruturas de dados "lineares", pois todas elas têm um início e um fim lógicos.</p><p>Quando começamos a aprender sobre <code>árvores</code> e <code>grafos</code>, pode ficar bastante confuso. Neles, não armazenamos dados de forma linear. As duas estruturas armazenam dados de um modo específico.</p><p>Este artigo é para ajudá-lo a entender melhor a estrutura de dados de árvore e para esclarecer qualquer confusão que você possa ter sobre ela.</p><p>Nele, vamos aprender:</p><ul><li>O que é uma árvore</li><li>Exemplos de árvore</li><li>Sua terminologia e como ela funciona</li><li>Como implementar estruturas de árvore em código.</li></ul><p>Vamos começar esta jornada de aprendizagem :)</p><h3 id="defini-o"><strong>Definição</strong></h3><p>Ao começar a programar, é comum entender melhor as estruturas de dados lineares do que estruturas de dados como árvores e grafos.</p><p>As árvores são conhecidas como uma estrutura de dados não linear. Elas não armazenam dados de modo linear. Elas organizam os dados de modo hierárquico.</p><h3 id="vamos-examinar-exemplos-da-vida-real-"><strong>Vamos examinar exemplos da vida real!</strong></h3><p>O que quero dizer quando digo de modo hierárquico?</p><p>Imagine uma árvore genealógica com relacionamentos de todas as gerações: avós, pais, filhos, irmãos e assim por diante. Geralmente, organizamos as árvores genealógicas de modo hierárquico.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_MasdC5DmucEU2abIXQe45Q.jpeg" class="kg-image" alt="1_MasdC5DmucEU2abIXQe45Q" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_MasdC5DmucEU2abIXQe45Q.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_MasdC5DmucEU2abIXQe45Q.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>A minha árvore genealógica</figcaption></figure><p>O desenho acima é a minha árvore genealógica. Tossico, Akikazu, Hitomi e Takemi são meus avós.</p><p>Toshiaki e Juliana são meus pais.</p><p>TK, Yuji, Bruno e Kaio são os filhos dos meus pais (eu e meus irmãos).</p><p>A estrutura de uma organização é outro exemplo de uma hierarquia.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_GsBCmW5E1GuJ3MpH3Zz0Ew.jpeg" class="kg-image" alt="1_GsBCmW5E1GuJ3MpH3Zz0Ew" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_GsBCmW5E1GuJ3MpH3Zz0Ew.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_GsBCmW5E1GuJ3MpH3Zz0Ew.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>A estrutura de uma empresa é um exemplo de uma hierarquia</figcaption></figure><p>Em HTML, o Modelo de Objeto de Documento (em inglês, DOM, ou <em>Document Object Model</em>) funciona como uma árvore.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_dLXUdR4NuIZG8GJdu_Cinw.jpeg" class="kg-image" alt="1_dLXUdR4NuIZG8GJdu_Cinw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_dLXUdR4NuIZG8GJdu_Cinw.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_dLXUdR4NuIZG8GJdu_Cinw.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>Modelo de Objeto de Documento (DOM - Document Object Model)</figcaption></figure><p>A tag HTML contém outras tags. Temos uma tag <code>head</code> e uma tag <code>body</code>. Essas tags contêm elementos específicos. A tag <code>head</code> tem tags <code>meta</code> e tags <code>title</code>. A tag <code>body</code> tem elementos que aparecem na interface do usuário, como <code>h1</code>, <code>a</code>, <code>li</code>, entre outros.</p><h3 id="uma-defini-o-t-cnica"><strong>Uma definição técnica</strong></h3><p>Uma <code>árvore</code> é um conjunto de entidades chamadas <code>nós</code>. Os nós são conectados por <code>arestas</code>. Cada <code>nó</code> contém um <code>valor</code> ou <code>dados</code> e pode ou não ter um <code>nó filho</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_3WN7tIQ-kNBQmY9MgvTuOA.jpeg" class="kg-image" alt="1_3WN7tIQ-kNBQmY9MgvTuOA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_3WN7tIQ-kNBQmY9MgvTuOA.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_3WN7tIQ-kNBQmY9MgvTuOA.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>O <code>primeiro nó</code> da árvore é chamado de <code>raiz</code>. Se este <code>nó raiz</code> é conectado por outro nó, a raiz é então um <code>nó pai</code> e o nó conectado é um <code>nó filho</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_9AtR3bhhlMJxQlaUVEQgrw.jpeg" class="kg-image" alt="1_9AtR3bhhlMJxQlaUVEQgrw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_9AtR3bhhlMJxQlaUVEQgrw.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_9AtR3bhhlMJxQlaUVEQgrw.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>As ligações são chamadas de arestas</figcaption></figure><p>Todos os <code>nós das árvores</code> são conectados por links chamados <code>arestas</code>. Essa é uma parte importante das árvores, porque elas gerenciam a relação entre os nós.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_j5qKwIxKcEjoxy88EOc1Rg.jpeg" class="kg-image" alt="1_j5qKwIxKcEjoxy88EOc1Rg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_j5qKwIxKcEjoxy88EOc1Rg.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_j5qKwIxKcEjoxy88EOc1Rg.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>As <code>folhas</code> são os últimos nós de uma árvore. Elas são os nós sem filhos. Como árvores reais, temos a <code>raiz</code>, os <code>ramos</code> e, finalmente, as <code>folhas</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_c9_5uMUsIy4Q3OA7Q8bJiw.jpeg" class="kg-image" alt="1_c9_5uMUsIy4Q3OA7Q8bJiw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_c9_5uMUsIy4Q3OA7Q8bJiw.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_c9_5uMUsIy4Q3OA7Q8bJiw.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Outros conceitos importantes a serem entendidos são <code>altura</code> e <code>profundidade</code>.</p><p>A <code>altura</code> de uma <code>árvore</code> é o tamanho do caminho mais longo até uma folha.</p><p>A <code>profundidade</code> de um <code>nó</code> é o tamanho do caminho percorrido do nó até a <code>raiz</code>.</p><h3 id="resumo-da-terminologia"><strong>Resumo da terminologia</strong></h3><ul><li>A <strong>raiz</strong> é o <code>nó</code> mais alto da <code>árvore</code></li><li>A <strong>aresta</strong> é a ligação entre dois <code>nós</code></li><li>O <strong>filho</strong> é um <code>nó</code> que tem um <code>nó pai</code></li><li>O <strong>pai</strong> é um <code>nó</code> que tem uma <code>aresta</code> apontando para um <code>nó filho</code></li><li>A <strong>folha</strong> é um <code>nó</code> que não tem <code>nós filhos</code> na <code>árvore</code></li><li>A <strong>altura</strong> é o tamanho do caminho mais longo até uma <code>folha</code></li><li>A <strong>profundidade</strong> é o tamanho do caminho percorrido do <code>nó</code> até a <code>raiz</code></li></ul><h3 id="-rvores-bin-rias"><strong>Árvores binárias</strong></h3><p>Agora, vamos discutir um tipo específico de <code>árvore</code>. Nós a chamamos de <code>árvore binária</code>.</p><blockquote><em>"Na ciência da computação, uma árvore binária é uma estrutura de dados em árvore na qual cada nó tem, no máximo, dois filhos, que são referidos como o </em>filho<em> da esquerda e o </em>filho<em> da direita". - <a href="https://pt.wikipedia.org/wiki/%C3%81rvore_bin%C3%A1ria">Wikipédia</a></em></blockquote><p>Então, vejamos um exemplo de árvore binária.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ofbwuz4inpf2OlB-l9gtHw.jpeg" class="kg-image" alt="1_ofbwuz4inpf2OlB-l9gtHw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_ofbwuz4inpf2OlB-l9gtHw.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ofbwuz4inpf2OlB-l9gtHw.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><h3 id="vamos-programar-uma-rvore-bin-ria"><strong>Vamos programar uma árvore binária</strong></h3><p>A primeira coisa que precisamos ter em mente quando implementamos uma árvore binária é o fato de ela ser uma coleção de nós. Cada nó tem três atributos: <code>value</code>, <code>left_child</code> (o filho da esquerda) e <code>right_child</code> (o filho da direita).</p><p>Como implementamos uma árvore binária simples que inicializa com estas três propriedades?</p><p>Vamos dar uma olhada.</p><pre><code class="language-py">class BinaryTree:
    def __init__(self, value):
        self.value = value
        self.left_child = None
        self.right_child = None</code></pre><p>Aqui está. Esta é a nossa classe de árvore binária.</p><p>Quando instanciamos um objeto, passamos <code>value</code> (os dados do nó) como um parâmetro. Olhe para <code>left_child</code> e para <code>right_child</code>. Os dois estão definidos como <code>None</code> (Nenhum).</p><p>Por quê?</p><p>Porque quando criamos nosso <code>nó</code>, ele não tem filhos. Temos apenas os dados do nó.</p><p>Vamos testá-lo:</p><pre><code class="language-py">tree = BinaryTree('a')
print(tree.value) # a
print(tree.left_child) # None
print(tree.right_child) # None</code></pre><p>É isso.</p><p>Podemos passar a string 'a' como o valor para nosso nó da árvore binária. Se imprimirmos <code>value</code>, <code>left_child</code> e <code>right_child</code>, podemos ver os valores.</p><p>Vamos para a parte de inserção. O que precisamos fazer aqui?</p><p>Vamos implementar um método para inserir um novo <code>nó</code> à direita e à esquerda.</p><p>Aqui estão as regras:</p><ul><li>Se o nó atual não tiver um filho da esquerda, criamos apenas um nó e o configuramos como <code>left_child</code> do nó atual.</li><li>Se ele tiver o filho da esquerda, criamos um nó e o colocamos no lugar da filho da esquerda atual. Alocamos este nó filho da esquerda como o novo nó <code>left_child</code>.</li></ul><p>Vamos representar isso com um desenho :)</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ofbwuz4inpf2OlB-l9gtHw-1.jpeg" class="kg-image" alt="1_ofbwuz4inpf2OlB-l9gtHw-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_ofbwuz4inpf2OlB-l9gtHw-1.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ofbwuz4inpf2OlB-l9gtHw-1.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Aqui está o código:</p><pre><code class="language-py">def insert_left(self, value):
    if self.left_child == None:
        self.left_child = BinaryTree(value)
    else:
        new_node = BinaryTree(value)
        new_node.left_child = self.left_child
        self.left_child = new_node</code></pre><p>Novamente, se o nó atual não tiver um filho da esquerda, apenas criamos um nó e o configuramos como <code>left_child</code> do nó atual. Como alternativa, criamos um nó e o colocamos no lugar do <code>left_child</code> atual. Alocamos este nó como o novo nó <code>left_child</code>.</p><p>Fazemos a mesma coisa para inserir um nó do filho da direita.</p><pre><code class="language-py">def insert_right(self, value):
    if self.right_child == None:
        self.right_child = BinaryTree(value)
    else:
        new_node = BinaryTree(value)
        new_node.right_child = self.right_child
        self.right_child = new_node</code></pre><p>Feito. :)</p><p>Porém, temos que testá-lo.</p><p>Vamos construir a seguinte <code>árvore</code>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_V_EUgNXVc8Wy9H1-JoqT3g.jpeg" class="kg-image" alt="1_V_EUgNXVc8Wy9H1-JoqT3g" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_V_EUgNXVc8Wy9H1-JoqT3g.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_V_EUgNXVc8Wy9H1-JoqT3g.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Para resumir a ilustração desta árvore:</p><ul><li>o <code>nó</code> <code>a</code> será a <code>raiz</code> da nossa <code>árvore binária</code></li><li>o <code>filho da esquerda</code> de <code>a</code> é o <code>nó</code> <code>b</code></li><li>o <code>filho da direita</code> de <code>a</code> é o <code>nó</code> <code>c</code></li><li>o <code>filho da direita</code> de <code>b</code> é o <code>nó</code> <code>d</code> (o <code>nó</code> <code>b</code> não tem um <code>filho da esquerda</code>)</li><li>o <code>filho da esquerda</code> de <code>c</code> é o <code>nó</code> <code>e</code></li><li>o <code>filho da direita</code> de <code>c</code> é o <code>nó</code> <code>f</code></li><li>tanto o <code>nó</code> <code>e</code> como o <code>nó</code> <code>f</code> não têm filhos</li></ul><p>Portanto, aqui está o código para a árvore:</p><pre><code class="language-py">a_node = BinaryTree('a')
a_node.insert_left('b')
a_node.insert_right('c')

b_node = a_node.left_child
b_node.insert_right('d')

c_node = a_node.right_child
c_node.insert_left('e')
c_node.insert_right('f')

d_node = b_node.right_child
e_node = c_node.left_child
f_node = c_node.right_child

print(a_node.value) # a
print(b_node.value) # b
print(c_node.value) # c
print(d_node.value) # d
print(e_node.value) # e
print(f_node.value) # f</code></pre><p>A inserção está feita.</p><p>Agora temos que pensar na travessia da árvore.</p><p>Temos aqui <strong>duas opções:</strong> <strong>a</strong> <strong>Busca em Profundidade (DFS - Depth-First Search)</strong> e <strong>a Busca em Largura (BFS - Breadth-First Search)</strong>.</p><ul><li><strong>DFS</strong> "é um algoritmo para fazer uma travessia ou pesquisar a estrutura de dados em árvore. Ele começa pela raiz e explora o máximo possível ao longo de cada ramo antes de retroceder". – <em><a href="https://pt.wikipedia.org/wiki/Busca_em_profundidade">Wikipedia</a></em></li><li><strong>BFS</strong> "é um algoritmo para fazer uma travessia ou pesquisar a estrutura de dados em árvore. Ele começa na raiz da árvore e explora os nós vizinhos primeiro antes de passar para os vizinhos do nível seguinte". – <em><a href="https://pt.wikipedia.org/wiki/Busca_em_largura">Wikipedia</a></em></li></ul><p>Portanto, vamos analisar os tipos de travessia de árvores.</p><h3 id="busca-em-profundidade-dfs-depth-first-search-"><strong>Busca em Profundidade (DFS - Depth-First Search)</strong></h3><p>A <strong>DFS</strong> explora todo um caminho até uma folha antes de retroceder (<strong>backtracking)</strong> e explorar outro caminho. Vamos dar uma olhada em um exemplo com este tipo de travessia.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg.jpeg" class="kg-image" alt="1_-sCuUx3R9e1ougu2pGdThg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_-sCuUx3R9e1ougu2pGdThg.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>O resultado para este algoritmo será 1–2–3–4–5–6–7.</p><p>Por quê?</p><p>Vamos dividi-lo em partes.</p><ol><li>Comece na `raiz` (1). Imprima-a.</li></ol><p>2. Vá para o <code>filho da esquerda</code> (2). Imprima-o.</p><p>3. Então, vá para o <code>filho da esquerda</code> (3). Imprima-o. (Este nó não tem filhos)</p><p>4. Retroceda e vá para <code>filho da direita</code> (4). Imprima-o. (Este nó não tem filhos)</p><p>5. Retroceda, vá para nó <code>raiz</code> e vá para o <code>filho da direita</code> (5). Imprima-o.</p><p>6. Vá para o <code>filho da esquerda</code> (6). Imprima-o. (Este nó não tem filhos)</p><p>7. Retroceda e vá para <code>filho da direita</code> (7). Imprima-o. (Este nó não tem filhos)</p><p>8. Feito.</p><p>Quando vamos a fundo até uma folha e retrocedemos, isso é chamado de algoritmo <strong>DFS</strong>.</p><p>Agora que estamos familiarizados com esse algoritmo de travessia, discutiremos os tipos de <strong>DFS</strong>: pré-ordem, em ordem e pós-ordem.</p><h3 id="pr-ordem"><strong>Pré-ordem</strong></h3><p>Isso é exatamente o que fizemos no exemplo acima.</p><ol><li>Imprimir o valor do <code>nó</code>.</li><li>Ir para o <code>filho da esquerda</code> e imprimi-lo se, e somente se, tiver um <code>filho da esquerda</code>.</li><li>Ir para o <code>filho da direita</code> e imprimi-lo se, e somente se, tiver um <code>filho da direita</code>.</li></ol><pre><code class="language-py">def pre_order(self):
    print(self.value)

    if self.left_child:
        self.left_child.pre_order()

    if self.right_child:
        self.right_child.pre_order()</code></pre><h3 id="em-ordem"><strong>Em ordem</strong></h3><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg-1.jpeg" class="kg-image" alt="1_-sCuUx3R9e1ougu2pGdThg-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_-sCuUx3R9e1ougu2pGdThg-1.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg-1.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>O resultado do algoritmo em ordem para este exemplo da árvore é 3–2–4–1–6–5–7.</p><p>Começamos da esquerda primeiro, depois pegamos o do meio e, por fim, o da direita.</p><p>Agora, vamos transformar isso em código.</p><pre><code class="language-py">def in_order(self):
    if self.left_child:
        self.left_child.in_order()

    print(self.value)

    if self.right_child:
        self.right_child.in_order()</code></pre><ol><li>Vá para o <code>filho da esquerda</code> e imprima-o se, e somente se, tiver um <code>filho da esquerda</code>.</li><li>Imprima o valor do <code>nó</code></li><li>Vá para o <code>filho da direita</code> e imprima-o se, e somente se, tiver um <code>filho da direita</code>.</li></ol><h3 id="p-s-ordem"><strong>Pós-ordem</strong></h3><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg-2.jpeg" class="kg-image" alt="1_-sCuUx3R9e1ougu2pGdThg-2" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_-sCuUx3R9e1ougu2pGdThg-2.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg-2.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>O resultado do algoritmo de pós-ordem para este exemplo de árvore é 3–4–2–6–7–5–1.</p><p>Começamos com a esquerda, seguindo da direita e depois o meio.</p><p>Vamos transformar isso em código.</p><pre><code>def post_order(self):
    if self.left_child:
        self.left_child.post_order()

    if self.right_child:
        self.right_child.post_order()

    print(self.value)</code></pre><ol><li>Vá para o <code>filho da esquerda</code> e imprima-o se, e somente se, tiver um <code>filho da esquerda</code>.</li><li>Vá até o <code>filho da direita</code> e imprima-o se, e somente se, tiver um <code>filho da direita</code>.</li><li>Imprima o valor do <code>nó</code></li></ol><h3 id="busca-em-largura-bfs-breadth-first-search-"><strong>Busca em largura (BFS - Breadth-First Search)</strong></h3><p>O algoritmo <strong>BFS</strong> atravessa a <code>árvore</code> nível por nível e profundidade por profundidade.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ZNxp_NkRZLCeak85rreebA.jpeg" class="kg-image" alt="1_ZNxp_NkRZLCeak85rreebA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_ZNxp_NkRZLCeak85rreebA.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ZNxp_NkRZLCeak85rreebA.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Aqui está um exemplo que ajuda a explicar melhor este algoritmo:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg-3.jpeg" class="kg-image" alt="1_-sCuUx3R9e1ougu2pGdThg-3" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_-sCuUx3R9e1ougu2pGdThg-3.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_-sCuUx3R9e1ougu2pGdThg-3.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Portanto, atravessamos nível por nível. Neste exemplo, o resultado é 1–2–5–3–4–6–7.</p><ul><li>Nível/Profundidade 0: somente o <code>nó</code> com valor 1</li><li>Nível/Profundidade 1: <code>nós</code> com valores 2 e 5</li><li>Nível/Profundidade 2: <code>nós</code> com valores 3, 4, 6, e 7</li></ul><p>Agora, vamos transformar isso em código.</p><pre><code class="language-py">def bfs(self):
    queue = Queue()
    queue.put(self)

    while not queue.empty():
        current_node = queue.get()
        print(current_node.value)

        if current_node.left_child:
            queue.put(current_node.left_child)

        if current_node.right_child:
            queue.put(current_node.right_child)</code></pre><p>Para implementar um algoritmo de <strong>BFS</strong>, usamos a estrutura de dados da fila para ajudar.</p><p>Como funciona?</p><p>Aqui está a explicação.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_A4yGfEoiqcZ-COvAfr2CWQ.jpeg" class="kg-image" alt="1_A4yGfEoiqcZ-COvAfr2CWQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_A4yGfEoiqcZ-COvAfr2CWQ.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_A4yGfEoiqcZ-COvAfr2CWQ.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><ol><li>Primeiro adicione o <code>nó raiz</code> na <code>fila</code> (<em>Queue</em>) com o método <code>put</code>.</li><li>Itere enquanto a <code>fila</code> não estiver vazia.</li><li>Obtenha o primeiro <code>nó</code> na <code>fila</code>, depois imprima o seu valor.</li><li>Acrescentar o <code>filho da esquerda</code> e o <code>filho da direita</code> na fila (se o nó atual tiver filhos).</li><li>Feito. Imprimiremos o valor de cada <code>nó</code>, nível por nível, com nosso ajudante de <code>fila</code>.</li></ol><h3 id="-rvore-bin-ria-de-busca"><strong>Árvore binária de busca</strong></h3><blockquote><em>"Uma árvore binária de busca é às vezes chamada de árvore binária ordenada ou classificada, e mantém seus valores em ordem, para que a busca e as outras operações possam usar o princípio da busca binária" - <a href="https://pt.wikipedia.org/wiki/%C3%81rvore_bin%C3%A1ria_de_busca">Wikipedia</a></em></blockquote><p>Uma propriedade importante de uma <code>árvore binária de busca</code> é que o valor de um nó da árvore binária de busca é maior que o valor dos descendentes do seu <code>filho da esquerda</code>, mas menor que o valor dos descendentes de seu <code>filho da direita</code>".</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_mslH9VtVUN9Hs983XxUN5A.jpeg" class="kg-image" alt="1_mslH9VtVUN9Hs983XxUN5A" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_mslH9VtVUN9Hs983XxUN5A.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_mslH9VtVUN9Hs983XxUN5A.jpeg 727w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Aqui está uma descrição da ilustração acima:</p><ul><li><strong>A</strong> está invertido. A <code>subárvore</code> 7-5-8-6 precisa estar do lado direito e a <code>subárvore</code> 2-1-3 precisa estar do lado esquerdo.</li><li><strong>B</strong> é a única opção correta. Ela satisfaz a propriedade da <code>árvore binária de busca</code>.</li><li><strong>C</strong> tem um problema: o <code>nó</code> com o valor 4. Ele precisa estar do lado esquerdo da <code>raiz</code> porque é menor do que 5.</li></ul><h3 id="vamos-programar-uma-rvore-de-busca-bin-ria-"><strong>Vamos programar uma árvore de busca binária!</strong></h3><p>Agora é hora de programar!</p><p>O que veremos aqui? Vamos inserir novos nós, procurar um valor, deletar nós e o equilíbrio da <code>árvore</code>.</p><p>Vamos começar.</p><h3 id="inser-o-adicionar-novos-n-s-nossa-rvore"><strong>Inserção: adicionar novos nós à nossa árvore</strong></h3><p>Imagine que temos uma <code>árvore</code> vazia e que queremos adicionar novos <code>nós</code> com os seguintes valores nesta ordem: 50, 76, 21, 4, 32, 100, 64, 52.</p><p>A primeira coisa que precisamos saber é se 50 é a <code>raiz</code> de nossa árvore.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_fxSlTwgQSN_DlzfEmcxqQg.jpeg" class="kg-image" alt="1_fxSlTwgQSN_DlzfEmcxqQg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_fxSlTwgQSN_DlzfEmcxqQg.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_fxSlTwgQSN_DlzfEmcxqQg.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Podemos agora começar a inserir nó por nó.</p><ul><li>76 é maior que 50, portanto insira 76 no lado direito.</li><li>21 é menor do que 50, portanto insira 21 no lado esquerdo.</li><li>4 é menor do que 50. O <code>nó</code> com valor 50 tem um <code>filho da esquerda</code> 21. Como 4 é menor do que 21, insira-o no lado esquerdo deste <code>nó</code>.</li><li>32 é menor do que 50. O <code>nó</code> com valor 50 tem um <code>filho da esquerda</code> 21. Como 32 é maior que 21, insira 32 no lado direito deste <code>nó</code>.</li><li>100 é maior que 50. O <code>nó</code> com valor 50 tem um <code>filho da direita</code> 76. Como 100 é maior que 76, insira 100 no lado direito deste <code>nó</code>.</li><li>64 é maior que 50. O <code>nó</code> com valor 50 tem um <code>filho da direita</code> 76. Como 64 é menor que 76, insira 64 no lado esquerdo deste <code>nó</code>.</li><li>52 é maior que 50. O <code>nó</code> com valor 50 tem um <code>filho da direita</code> 76. Como 52 é menor do que 76, o nó com valor 76 tem um <code>filho da esquerda</code> 64. 52 é menor do que 64, portanto insira 54 no lado esquerdo deste <code>nó</code>.</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_LlLDNx7wgJfH6VAGnyAbIQ.jpeg" class="kg-image" alt="1_LlLDNx7wgJfH6VAGnyAbIQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_LlLDNx7wgJfH6VAGnyAbIQ.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_LlLDNx7wgJfH6VAGnyAbIQ.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Você percebe um padrão aqui?</p><p>Vamos analisar.</p><ol><li>O valor do novo <code>nó</code> é maior ou menor que o do <code>nó</code> atual?</li><li>Se o valor do novo <code>nó</code> for maior que o <code>nó</code> atual, vá para a <code>subárvore</code> à direita. Se o <code>nó</code> atual não tiver um <code>filho da direita</code>, insira-o lá ou retroceda para o passo nº 1.</li><li>Se o valor do novo <code>nó</code> for menor do que o <code>nó</code> atual, vá para a <code>subárvore</code> à esquerda. Se o <code>nó</code> atual não tiver um <code>filho da esquerda</code>, insira-o lá ou retroceda para o passo nº 1.</li><li>Não tratamos de casos especiais aqui. Quando o valor de um novo <code>nó</code> for igual ao valor atual do <code>nó</code>, use a regra número 3. Considere a inserção de valores iguais no lado esquerdo da <code>subárvore</code>.</li></ol><p>Agora vamos transformar isso em código.</p><pre><code class="language-py">class BinarySearchTree:
    def __init__(self, value):
        self.value = value
        self.left_child = None
        self.right_child = None

    def insert_node(self, value):
        if value &lt;= self.value and self.left_child:
            self.left_child.insert_node(value)
        elif value &lt;= self.value:
            self.left_child = BinarySearchTree(value)
        elif value &gt; self.value and self.right_child:
            self.right_child.insert_node(value)
        else:
            self.right_child = BinarySearchTree(value)</code></pre><p>Parece muito simples.</p><p>A parte poderosa desse algoritmo é a parte de recursão, que está nas linhas 9 e 13. As duas linhas de código chamam o método <code>insert_node</code> e o utilizam para seus <code>filhos à esquerda</code> e <code>filhos à direita</code>, respectivamente. As linhas 11 e 15 são as que fazem a inserção para cada <code>filho</code>.</p><h3 id="vamos-procurar-o-valor-do-n-ou-n-o-"><strong>Vamos procurar o valor do nó... ou não...</strong></h3><p>O algoritmo que construiremos agora é o de buscas. Para um determinado valor (número inteiro), diremos se nossa árvore de busca binária tem ou não esse valor.</p><p>Um item importante a ser observado é como definimos o algoritmo de <strong>inserção de árvores</strong>. Primeiro, temos nosso <code>nó raiz</code>. Todos os nós da <code>subárvore</code> da esquerda terão valores menores que o <code>nó raiz</code>. Todos os nós da <code>subárvore</code> da direita terão valores maiores que o <code>nó raiz</code>.</p><p>Vamos dar uma olhada em um exemplo.</p><p>Imagine que temos esta <code>árvore</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_LlLDNx7wgJfH6VAGnyAbIQ-1.jpeg" class="kg-image" alt="1_LlLDNx7wgJfH6VAGnyAbIQ-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_LlLDNx7wgJfH6VAGnyAbIQ-1.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_LlLDNx7wgJfH6VAGnyAbIQ-1.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Agora, queremos saber se temos um nó baseado no valor 52.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_NwvTrpKiJWb1u2yAY-nnAA.jpeg" class="kg-image" alt="1_NwvTrpKiJWb1u2yAY-nnAA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_NwvTrpKiJWb1u2yAY-nnAA.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_NwvTrpKiJWb1u2yAY-nnAA.jpeg 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Vamos analisar.</p><ol><li>Começamos com o <code>nó raiz</code> como nosso <code>nó</code> atual. O valor dado é menor do que o valor do <code>nó</code> atual? Se sim, buscaremos esse valor na <code>subárvore</code> da esquerda.</li><li>O valor dado é maior do que o valor do <code>nó</code> atual? Se sim, buscaremos esse valor na <code>subárvore</code>da direita.</li><li>Se as regras nº 1 e 2 forem falsas, podemos comparar o valor do <code>nó</code> atual e o valor dado se forem iguais. Se a comparação retornar <code>True</code>, podemos dizer: "Sim! Nossa árvore tem o valor dado", caso contrário, dizemos: "Não, não tem".</li></ol><p>Agora, vamos transformar isso em código.</p><pre><code class="language-py">class BinarySearchTree:
    def __init__(self, value):
        self.value = value
        self.left_child = None
        self.right_child = None

    def find_node(self, value):
        if value &lt; self.value and self.left_child:
            return self.left_child.find_node(value)
        if value &gt; self.value and self.right_child:
            return self.right_child.find_node(value)

        return value == self.value</code></pre><p>Vamos detalhar o código:</p><ul><li>As linhas 8 e 9 estão sob a regra nº 1.</li><li>As linhas 10 e 11 estão sob a regra nº 2.</li><li>A linha 13 está sob a regra nº 3.</li></ul><p>Como testamos isso?</p><p>Vamos criar a nossa <code>árvore binária de busca</code>, inicializando o <code>nó raiz</code> com o valor 15.</p><pre><code class="language-py">bst = BinarySearchTree(15)</code></pre><p>Agora, vamos inserir muitos nós novos.</p><pre><code class="language-py">bst.insert_node(10)
bst.insert_node(8)
bst.insert_node(12)
bst.insert_node(20)
bst.insert_node(17)
bst.insert_node(25)
bst.insert_node(19)</code></pre><p>Para cada nó inserido, testaremos se o nosso método <code>find_node</code> realmente funciona.</p><pre><code class="language-py">print(bst.find_node(15)) # True
print(bst.find_node(10)) # True
print(bst.find_node(8)) # True
print(bst.find_node(12)) # True
print(bst.find_node(20)) # True
print(bst.find_node(17)) # True
print(bst.find_node(25)) # True
print(bst.find_node(19)) # True</code></pre><p>Sim, ele funciona para esses valores dados! Vamos testar para um valor que não existe em nossa árvore de busca binária.</p><pre><code class="language-py">print(bst.find_node(0)) # False</code></pre><p>Sim. Nossa busca está feita.</p><h3 id="elimina-o-remo-o-e-organiza-o"><strong>Eliminação: remoção e organização</strong></h3><p>A eliminação é um algoritmo mais complexo porque precisamos tratar de casos diferentes. Para um determinado valor, precisamos remover o <code>nó</code> com este valor. Imagine os seguintes cenários para este <code>nó</code>: ele não tem <code>filhos</code>, tem um único <code>filho</code> ou tem <code>dois filhos</code>.</p><ul><li><strong>Cenário nº 1</strong>: um <code>nó</code> sem <code>filhos</code> (<code>nó folha</code>).</li></ul><pre><code class="language-py">#        |50|                              |50|
#      /      \                           /    \
#    |30|     |70|   (DELETE 20) ---&gt;   |30|   |70|
#   /    \                                \
# |20|   |40|                             |40|</code></pre><p>Se o <code>nó</code> que queremos excluir não tem filhos, simplesmente o excluímos. O algoritmo não precisa reorganizar a <code>árvore</code>.</p><ul><li><strong>Cenário nº 2</strong>: um <code>nó</code> com apenas um filho (<code>filho da esquerda</code> ou <code>filho da direita</code>).</li></ul><pre><code class="language-py">#        |50|                              |50|
#      /      \                           /    \
#    |30|     |70|   (DELETE 30) ---&gt;   |20|   |70|
#   /            
# |20|</code></pre><p>Neste caso, nosso algoritmo precisa fazer com que o pai do <code>nó</code> aponte para o nó <code>filho</code>. Se o nó for o <code>filho da esquerda</code>, fazemos com que o pai do <code>filho da esquerda</code> aponte para o <code>filho</code>. Se o <code>nó</code> for o <code>filho da direita</code> do seu pai, fazemos com que o pai do <code>filho da direita</code> aponte para o <code>filho</code>.</p><ul><li><strong>Cenário nº 3</strong>: uim <code>nó</code> com dois filhos.</li></ul><pre><code class="language-py">#        |50|                              |50|
#      /      \                           /    \
#    |30|     |70|   (DELETE 30) ---&gt;   |40|   |70|
#   /    \                             /
# |20|   |40|                        |20|</code></pre><p>Quando o <code>nó</code> tem dois filhos, precisamos encontrar o <code>nó</code> com o valor mínimo, a começar pelo <code>filho da direita</code> do <code>nó</code>. Colocaremos este <code>nó</code> com o valor mínimo no lugar do <code>nó</code> que queremos remover.</p><p>É hora de transformar isso em código.</p><pre><code class="language-py">def remove_node(self, value, parent):
    if value &lt; self.value and self.left_child:
        return self.left_child.remove_node(value, self)
    elif value &lt; self.value:
        return False
    elif value &gt; self.value and self.right_child:
        return self.right_child.remove_node(value, self)
    elif value &gt; self.value:
        return False
    else:
        if self.left_child is None and self.right_child is None and self == parent.left_child:
            parent.left_child = None
            self.clear_node()
        elif self.left_child is None and self.right_child is None and self == parent.right_child:
            parent.right_child = None
            self.clear_node()
        elif self.left_child and self.right_child is None and self == parent.left_child:
            parent.left_child = self.left_child
            self.clear_node()
        elif self.left_child and self.right_child is None and self == parent.right_child:
            parent.right_child = self.left_child
            self.clear_node()
        elif self.right_child and self.left_child is None and self == parent.left_child:
            parent.left_child = self.right_child
            self.clear_node()
        elif self.right_child and self.left_child is None and self == parent.right_child:
            parent.right_child = self.right_child
            self.clear_node()
        else:
            self.value = self.right_child.find_minimum_value()
            self.right_child.remove_node(self.value, self)

        return True</code></pre><ol><li><strong>Primeiro</strong>: observe o <code>valor</code> dos parâmetros e o <code>pai</code>. Queremos encontrar o <code>nó</code> que tem este <code>valor</code>. O <code>nó pai</code> é importante para a remoção do <code>nó</code>.</li><li><strong>Segundo</strong>: observe o valor de retorno. Nosso algoritmo retornará um valor booleano. Ele retorna <code>True</code> se encontrar o nó e o remove. Caso contrário, ele retornará <code>False</code></li><li><strong>Da linha 2 à linha 9:</strong> começamos a procurar o <code>nó</code> que tem o <code>valor</code> que estamos procurando. Se o <code>valor</code> for menor que o <code>valor atual</code>, vamos para a <code>subárvore da esquerda</code>, recursivamente (se, e somente se, o <code>nó atual</code> tiver um <code>filho da esquerda</code>). Se o <code>valor</code> for maior, vamos para a <code>subárvore da direita</code>, recursivamente.</li><li><strong>Linha 10:</strong> começamos a pensar sobre o algoritmo de <code>remoção</code>.</li><li><strong>Da linha 11 à linha 13:</strong> cobrimos o <code>nó</code> sem <code>filhos</code>. É o <code>filho da esquerda</code> do seu <code>pai</code>. Removemos o <code>nó</code> definindo o <code>filho da esquerda</code> do <code>pai</code> como <code>None</code>.</li><li><strong>Linhas 14 e 15:</strong> cobrimos o <code>nó</code> sem filhos. É o <code>filho da direita</code> do seu <code>pai</code>. Removeremos o <code>nó</code> definindo o <code>filho da direita</code> do <code>pai</code> como <code>None</code>.</li><li><strong>Método de limpeza do nó: m</strong>ostrarei o código de <code>clear_node</code> abaixo. Ele define os nós do <code>filho da esquerda</code>, do <code>filho da direita</code> e o valor do <code>nó</code> para <code>None</code>.</li><li><strong>Da linha 16 à linha 18:</strong> cobrimos o <code>nó</code> com apenas um <code>filho</code> (<code>filho da esquerda</code>). É o <code>filho da esquerda</code> do seu pai. Ajustamos o <code>filho da esquerda</code> do <code>pai</code> para o <code>filho da esquerda</code> do <code>nó</code> (o único filho que ele tem).</li><li><strong>Da linha 19 à linha 21:</strong> cobrimos o <code>nó</code> com apenas um <code>filho</code> (<code>filho da esquerda</code>), e ele é o <code>filho da direita</code> do seu <code>pai</code>. Configuramos o <code>filho da direita</code> do <code>pai</code> para o <code>filho da esquerda</code> do <code>nó</code> (o único <code>filho</code> que ele tem).</li><li><strong>Da linha 22 à linha 24:</strong> cobrimos o <code>nó</code> com apenas um <code>filho</code> (<code>filho da direita</code>), e ele é o <code>filho da esquerda</code> do seu <code>pai</code>. Configuramos o <code>filho da esquerda</code> do <code>pai</code> para o <code>filho da direita</code> do <code>nó</code> (o único <code>filho</code> que ele tem).</li><li><strong>Da linha 25 à linha 27: </strong>cobrimos o <code>nó</code> com apenas um <code>filho</code> (<code>filho da direita</code>), e ele é o <code>filho da direita</code> do seu <code>pai</code>. Colocamos o <code>filho da direita</code> do <code>pai</code> no <code>filho da direita</code> do <code>nó</code> (o único <code>filho</code> que ele tem).</li><li><strong>Da linha 28 à linha 30:</strong> cobrimos o <code>nó</code> com o <code>filho da esquerda</code> e o <code>filho da direita</code>. Obtemos o <code>nó</code> com o menor <code>valor</code> (o código é mostrado abaixo) e o configuramos com o <code>valor</code> do nó atual. Termine removendo o menor <code>nó</code>.</li><li><strong>Linha 32:</strong> se encontrarmos o <code>nó</code> que estamos procurando, ele precisa retornar <code>True</code>. Da linha 11 à linha 31, tratamos desse caso. Então, basta retornar <code>True</code> e pronto.</li></ol><ul><li>Para usar o método <code>clear_node</code>: configure o valor <code>None</code> para todos os três atributos — (<code>value</code>, <code>left_child</code> e <code>right_child</code>)</li></ul><pre><code class="language-py">def clear_node(self):
    self.value = None
    self.left_child = None
    self.right_child = None</code></pre><ul><li>Para usar o método <code>find_minimum_value</code>: desça para a esquerda. Se não conseguirmos encontrar mais nós, encontramos o menor.</li></ul><pre><code class="language-py">def find_minimum_value(self):
    if self.left_child:
        return self.left_child.find_minimum_value()
    else:
        return self.value</code></pre><p>Agora vamos testá-lo.</p><p>Usaremos esta <code>árvore</code> para testar nosso algoritmo <code>remove_node</code>.</p><pre><code class="language-py">#        |15|
#      /      \
#    |10|     |20|
#   /    \    /    \
# |8|   |12| |17| |25|
#              \
#              |19|</code></pre><p>Vamos remover o <code>nó</code> com o <code>valor</code> 8. É um <code>nó</code> sem filho.</p><pre><code class="language-py">print(bst.remove_node(8, None)) # True
bst.pre_order_traversal()

#     |15|
#   /      \
# |10|     |20|
#    \    /    \
#   |12| |17| |25|
#          \
#          |19|</code></pre><p>Agora, vamos remover o <code>nó</code> com o valor 17. É um <code>nó</code> com apenas um filho.</p><pre><code class="language-py">print(bst.remove_node(17, None)) # True
bst.pre_order_traversal()

#        |15|
#      /      \
#    |10|     |20|
#       \    /    \
#      |12| |19| |25|</code></pre><p>Finalmente, removeremos um nó com dois filhos. Esta é a raiz da nossa árvore.</p><pre><code class="language-py">print(bst.remove_node(15, None)) # True
bst.pre_order_traversal()

#        |19|
#      /      \
#    |10|     |20|
#        \        \
#        |12|     |25|</code></pre><p>Os testes agora estão prontos. :)</p><h3 id="isso-tudo-por-enquanto-"><strong>Isso é tudo por enquanto!</strong></h3><p>Parabéns por terminar este conteúdo denso. É realmente difícil entender um conceito que não conhecemos, mas você conseguiu. :)</p><p>Este é mais um passo adiante na minha jornada de aprendizagem e domínio de algoritmos e estruturas de dados. Você pode ver a documentação de minha jornada completa aqui na minha publicação <a href="https://medium.com/the-renaissance-developer"><strong>Renaissance Developer</strong></a> (em inglês).</p><p>Divirta-se, continue aprendendo e programando.</p><p><a href="https://twitter.com/LeandroTk_" rel="noopener">Twitter</a> e <a href="https://github.com/LeandroTk" rel="noopener">Github</a> do autor. ☺</p><h3 id="recursos-adicionais-em-ingl-s-"><strong>Recursos adicionais (em inglês)</strong></h3><ul><li><a href="https://www.youtube.com/watch?v=qH6yxkw0u78&amp;index=25&amp;list=PL2_aWCzGMAwI3W_JlcBbtYTwiQSsOTa6P">Introdução à estrutura de dados em árvore, da </a><a href="https://www.youtube.com/watch?v=qH6yxkw0u78&amp;index=25&amp;list=PL2_aWCzGMAwI3W_JlcBbtYTwiQSsOTa6P" rel="noopener"><strong>mycodeschool</strong></a><strong> </strong></li><li><a href="https://medium.com/basecs/how-to-not-be-stumped-by-trees-5f36208f68a7">Como não ser atropelado pelas árvores, do talentoso Vaidehi Joshi</a></li><li><a href="http://www.cs.jhu.edu/~cohen/CS226/Lectures/Trees.pdf">Introdução às árvores, palestra do professor <strong>Jonathan Cohen</strong></a></li><li><a href="http://people.cs.ksu.edu/~schmidt/300s05/Lectures/Week7b.html">Introdução às árvores, palestra do professor <strong>David Schmidt</strong></a></li><li><a href="http://www.cs.cmu.edu/~clo/www/CMU/DataStructures/Lessons/lesson4_1.htm">Introdução às árvores, palestra do professor <strong>Victor Adamchik</strong></a></li><li><a href="https://www.youtube.com/watch?v=oSWTXtMglKE">Árvores com <strong>Gayle Laakmann McDowell</strong></a></li><li><a href="https://github.com/leandrotk/algorithms/blob/master/computer_science/data_structures/binary_tree/binary_tree.py">Implementação de árvores binárias</a> e <a href="https://github.com/leandrotk/algorithms/blob/master/computer_science/data_structures/binary_tree/test_binary_tree.py">testes</a>, por <strong><a href="https://www.freecodecamp.org/news/all-you-need-to-know-about-tree-data-structures-bceacb85490c/undefined">TK</a></strong></li><li><a href="https://www.coursera.org/learn/data-structures">Curso do Coursera: Estruturas de dados, da <strong>Universidade da Califórnia, San Diego</strong></a></li><li><a href="https://www.coursera.org/learn/data-structures-optimizing-performance">Curso do Coursera: Estruturas de Dados e desempenho, da <strong>Universidade da Califórnia, San Diego</strong></a></li><li><a href="https://www.youtube.com/playlist?list=PLTxllHdfUq4d-DE16EDkpeb8Z68DU7Z_Q">Conceitos e implementação da árvore binária de busca, de </a><a href="https://www.youtube.com/playlist?list=PLTxllHdfUq4d-DE16EDkpeb8Z68DU7Z_Q" rel="noopener"><strong>Paul Programming</strong></a></li><li><a href="https://github.com/leandrotk/algorithms/blob/master/computer_science/data_structures/binary_search_tree_without_node/binary_search_tree.py">Implementação da árvore binária de busca</a> e <a href="https://github.com/leandrotk/algorithms/blob/master/computer_science/data_structures/binary_search_tree_without_node/test_binary_search_tree.py">testes</a>, por <a href="https://www.freecodecamp.org/news/all-you-need-to-know-about-tree-data-structures-bceacb85490c/undefined"><strong>TK</strong></a></li><li><a href="http://www.geeksforgeeks.org/binary-search-tree-set-2-delete/">Algoritmo de remoção de nó da árvore binária de busca, de <strong>GeeksforGeeks</strong></a></li><li><a href="http://www.algolist.net/Data_structures/Binary_search_tree/Removal">Algoritmo de remoção de nó da árvore binária de busca, de <strong>Algolist</strong></a></li><li><a href="https://www.freecodecamp.org/news/learning-python-from-zero-to-hero-120ea540b567/">Aprendendo Python do zero ao herói</a></li><li><a href="https://en.wikipedia.org/wiki/Tree_traversal">Travessia de árvores, da <strong>Wikipédia</strong></a></li></ul><h3 id="recursos-adicionais-em-portugu-s-"><strong>Recursos adicionais (em português)</strong></h3><ul><li><a href="https://pt.wikipedia.org/wiki/%C3%81rvore_(estrutura_de_dados)">Árvore, da <strong>Wikipedia</strong></a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como funcionam as licenças de código aberto e como adicioná-las aos seus projetos ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Radu Raicea Recentemente, tivemos algumas notícias empolgantes para os desenvolvedores em todo o mundo. O Facebook mudou a licença de várias bibliotecas que eles desenvolvem. Eles mudaram de patentes BSD-3+ para MIT (Massachusetts Institute of Technology). Certo, mas o que significa? Quais são as implicações de diferentes licenças ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-funcionam-as-licencas-de-codigo-aberto-e-como-adiciona-las-a-seus-projetos-2/</link>
                <guid isPermaLink="false">6352a692191d0905ea418c81</guid>
                
                    <category>
                        <![CDATA[ Programação ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Sun, 27 Nov 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_FFYtzf28XKPFBdknfXf-jg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-open-source-licenses-work-and-how-to-add-them-to-your-projects-34310c3cf94/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How open source licenses work and how to add them to your projects</a>
      </p><p>Escrito por: Radu Raicea</p><p>Recentemente, tivemos algumas notícias empolgantes para os desenvolvedores em todo o mundo. O Facebook mudou a licença de várias bibliotecas que eles desenvolvem. Eles mudaram de patentes <strong>BSD-3+</strong> para <strong>MIT (Massachusetts Institute of Technology)</strong>.</p><p>Certo, mas o que significa? Quais são as implicações de diferentes licenças de código aberto?</p><p>Este artigo dará a você uma rápida compreensão das licenças populares. Ele também ensinará como aplicá-las aos seus projetos de código aberto no GitHub.</p><h3 id="a-autoridade"><strong>A autoridade</strong></h3><p>As licenças de código aberto mais populares têm um aspecto importante em comum. A <a href="https://opensource.org/">Iniciativa de Código Aberto (OSI - Open Source Initiative)</a> as aprovou.</p><p>A OSI foi formada em 1998 com o objetivo de promover o software de código aberto. Ela criou a <a href="https://opensource.org/osd">Definição de Código Aberto (OSD - Open Source Definition)</a> para definir o que significa um software de código aberto.</p><p>É assim que eles se descrevem:</p><blockquote><em>A Iniciativa de Código Aberto (OSI - Open Source Initiative) é uma organização sem fins lucrativos com escopo global formada para educar e defender os benefícios do código aberto e construir pontes entre os diferentes círculos da comunidade de código aberto.</em></blockquote><h3 id="as-licen-as"><strong>As licenças</strong></h3><p>A maioria das licenças de código aberto inclui as seguintes declarações:</p><ol><li>O software pode ser modificado, utilizado comercialmente e distribuído.</li><li>O software pode ser modificado e utilizado em particular.</li><li>Uma licença e um aviso de direitos autorais devem ser incluídos no software.</li><li>Os autores do software não fornecem nenhuma garantia com o software e não são responsáveis por nada.</li></ol><p>Passaremos pelas licenças mais populares, de modo a mostrar as mais restritivas e as mais permissivas (da perspectiva do usuário).</p><p></p><h4 id="gnu-general-public-license-licen-a-p-blica-geral-vers-o-3-gplv3-">GNU (General Public License ) – Licença Pública Geral, versão 3 (GPLv3)</h4><p>A <a href="https://www.gnu.org/licenses/gpl-3.0.html" rel="noopener">GPLv3</a> é uma das licenças mais restritivas. Ela oferece alta proteção para o autor do software.</p><ul><li>O código-fonte deve ser tornado <strong>público</strong> sempre que uma distribuição do software for feita.</li><li>As modificações do software devem ser liberadas sob a <strong>mesma licença</strong>.</li><li>As alterações feitas no código-fonte <strong>devem ser documentadas</strong>.</li><li>Se o material patenteado for usado na criação do software, ela concede aos usuários o direito de usá-lo. Se o usuário processar alguém pelo uso do material patenteado, ele perde o direito de usar o software.</li></ul><p>A<strong> </strong><a href="https://www.gnu.org/licenses/gpl-2.0.html" rel="noopener"><strong>GPLv2</strong></a> é também muito popular. A principal diferença em relação à GPLv3 é a cláusula sobre concessão de patentes.</p><p>Essa cláusula foi acrescentada na versão 3 para evitar que as empresas <a href="http://www.nytimes.com/2006/11/22/technology/22soft.html">cobrassem dos </a><a href="http://www.nytimes.com/2006/11/22/technology/22soft.html">usuários pelo uso de suas patentes</a> (texto em inglês).</p><p>Projetos populares que usam GPLv3 são o <a href="https://www.gnu.org/software/bash/"><strong>Bash</strong></a> e o <a href="https://www.gimp.org/"><strong>GIMP</strong></a>. O <strong><a href="https://github.com/torvalds/linux">Linux</a></strong> utiliza a GPLv2.</p><p><a href="https://www.freecodecamp.org/news/how-open-source-licenses-work-and-how-to-add-them-to-your-projects-34310c3cf94/undefined" rel="noopener">Ezequiel Foncubierta</a> apontou algo importante para as licenças GPL:</p><blockquote><em>A licença do seu código-fonte deve ser compatível com a licença do código-fonte aberto ao qual você está vinculado. Por exemplo, se seu código for proprietário, você não terá permissão para usar uma biblioteca sob a licença GPL. É aqui que as pessoas tendem a cometer mais erros.</em></blockquote><h3 id="licen-a-apache-2-0"><strong>Licença Apache 2.0</strong></h3><p><a href="https://www.apache.org/licenses/LICENSE-2.0">A licença Apache 2.0</a> oferece mais flexibilidade para os usuários.</p><ul><li>O código-fonte <strong>não precisa ser público</strong> quando uma distribuição do software é feita.</li><li>As modificações no software podem ser liberadas sob <strong>qualquer licença</strong>.</li><li>As alterações feitas no código fonte <strong>devem</strong> ser documentadas.</li><li>Ela oferece a mesma proteção de uso de patente que a GPLv3.</li><li>Ela proíbe explicitamente o uso de nomes de marcas registradas encontradas no projeto.</li></ul><p>Projetos populares usando a licença Apache 2.0 são o <a href="https://github.com/aosp-mirror/platform_system_core/blob/master/NOTICE" rel="noopener"><strong>Android</strong></a>, o <a href="https://httpd.apache.org" rel="noopener"><strong>Apache</strong></a> e o <a href="https://github.com/apple/swift" rel="noopener"><strong>Swift</strong></a>.</p><h3 id="distribui-o-de-software-da-berkeley-bsd-berkeley-software-distribution-"><strong>Distribuição de Software da Berkeley (BSD - Berkeley Software Distribution)</strong></h3><h4></h4><p>A BSD tem duas versões principais: a de <a href="https://opensource.org/licenses/BSD-2-Clause">2 cláusulas</a> e a de <a href="https://opensource.org/licenses/BSD-3-Clause">3 cláusulas</a> (textos em inglês). Ambas oferecem mais flexibilidade para os usuários do que a Licença Apache 2.0.</p><ul><li>O código-fonte <strong>não precisa ser público</strong> quando uma distribuição do software é feita.</li><li>As modificações no software podem ser liberadas sob <strong>qualquer licença</strong>.</li><li>As alterações feitas no código-fonte <strong>podem não</strong> ser documentadas.</li><li>Ela não oferece nenhuma posição explícita sobre o uso da patente.</li><li>A licença e o aviso de direitos autorais devem ser incluídos na documentação da <strong>versão compilada</strong> do código-fonte (em oposição a apenas no código-fonte).</li><li>A BSD de 3 cláusulas afirma que os nomes do autor e dos colaboradores não podem ser usados para promover produtos derivados do software sem permissão.</li></ul><p>Os projetos populares que usam a licença BSD são o <a href="https://github.com/golang/go" rel="noopener"><strong>Go</strong></a> (3 cláusulas), o <a href="https://www.freecodecamp.org/portuguese/news/p/3c2166e1-bbc9-40df-909f-62bbcec5a4fa/Pure.css">Pure.css</a> (3 cláusulas) e o <a href="https://github.com/getsentry/sentry" rel="noopener"><strong>Sentry</strong></a><strong> </strong>(3 cláusulas).</p><h3 id="licen-a-mit-massachusetts-institute-of-technology-"><strong>Licença MIT (Massachusetts Institute of Technology)</strong></h3><p>A <a href="https://mit-license.org" rel="noopener">MIT</a> é uma das licenças mais permissivas. É também a mais popular. Ela oferece uma proteção muito baixa para o autor do software.</p><ul><li>O código-fonte <strong>não precisa ser público</strong> quando uma distribuição do software é feita.</li><li>As modificações no software podem ser liberadas sob <strong>qualquer licença</strong>.</li><li>As alterações feitas no código-fonte <strong>podem não</strong> ser documentadas.</li><li>Ele não oferece nenhuma posição explícita sobre o uso da patente.</li></ul><p>Os projetos populares que utilizam a MIT são o <a href="https://www.freecodecamp.org/portuguese/news/p/3c2166e1-bbc9-40df-909f-62bbcec5a4fa/Angular.js">Angular.js</a>, o <a href="https://github.com/jquery/jquery" rel="noopener"><strong>jQuery</strong></a>, o <a href="https://github.com/rails/rails" rel="noopener"><strong>Rails</strong></a>, o <a href="https://github.com/twbs/bootstrap" rel="noopener"><strong>Bootstrap</strong></a> e muitos outros.</p><p>O <a href="https://www.freecodecamp.org/portuguese/news/p/3c2166e1-bbc9-40df-909f-62bbcec5a4fa/React.js">React.js</a> do Facebook tinha uma licença de patente BSD-3+ até 25 de setembro de 2017. Ela combinava a licença do BSD-3 com uma cláusula adicional sobre o uso de patentes.</p><p>Em resumo, se você processar o Facebook ou qualquer uma de suas subsidiárias, perderá o direito de usar o React (ou qualquer outro software sob a mesma licença).</p><p>O React agora é licenciado pela MIT. Agora, você pode processar o Facebook e ainda usar o React. Que alívio!</p><h3 id="aplicando-uma-licen-a-para-os-seus-projetos-de-c-digo-aberto"><strong>Aplicando uma licença para os seus projetos de código aberto</strong></h3><p>Licenciar os seus projetos é fácil. Você precisa apenas adicionar um <code>LICENSE</code>, <code>LICENSE.txt</code> ou <code>LICENSE.md</code> no diretório raiz do seu repositório.</p><p>O GitHub torna tudo ainda mais fácil:</p><ol><li>Abra o seu repositório GitHub em um navegador.</li><li>No diretório raiz, clique em <code><strong>Create new file</strong></code>.</li><li>Nomeie o arquivo "LICENSE".</li><li>Clique em <code><strong>Choose a license template</strong></code>.</li><li>Escolha uma das licenças (todas as mencionadas neste artigo estão lá).</li><li>Uma vez escolhido, clique em <code><strong>Review and submit</strong></code>.</li><li>Faça o <code><strong>commit</strong></code> do arquivo.</li></ol><h3 id="em-resumo-"><strong>Em resumo...</strong></h3><ul><li>Uma das licenças mais restritivas é a <strong>GPL</strong></li><li>Uma das licenças mais permissivas é a <strong>MIT</strong>.</li><li>Outras licenças populares são &nbsp;a <strong>licença Apache</strong> 2.0 e a <strong>BSD</strong>.</li><li>Para aplicar uma licença em seu projeto do GitHub, você precisa apenas criar um arquivo <code>LICENSE</code> usando os templates de licença do GitHub.</li></ul><p><strong>Confira também o artigo do autor sobre <a href="https://www.freecodecamp.org/news/how-i-used-python-to-find-interesting-people-on-medium-be9261b924b0">como ele usou o Python para encontrar pessoas interessantes para seguir no Medium</a> (texto em inglês)!</strong></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
