<?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[ Elizabete Nakamura - 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[ Elizabete Nakamura - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 19:22:13 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/author/elizabete/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Os melhores exemplos de React ]]>
                </title>
                <description>
                    <![CDATA[ O React (também conhecido como React.js) é uma das bibliotecas de desenvolvimento para front-end em JavaScript mais populares. Aqui está uma coleção de sintaxe e uso do React que você pode usar como um guia prático ou referência. Exemplo de componente do React Os componentes são reutilizáveis no React.js. Você ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/os-melhores-exemplos-de-react/</link>
                <guid isPermaLink="false">648a9b25d1454605b613f40f</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Sun, 02 Jul 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/5f9c9f29740569d1a4ca4119.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/react-examples-reactjs/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The Best React Examples</a>
      </p><p>O React (também conhecido como React.js) é uma das bibliotecas de desenvolvimento para <em>front-end</em> em JavaScript mais populares. Aqui está uma coleção de sintaxe e uso do React que você pode usar como um guia prático ou referência.</p><h2 id="exemplo-de-componente-do-react"><strong>Exemplo de componente do React</strong></h2><p>Os componentes são reutilizáveis no React.js. Você pode injetar valores nas <em>props</em>, conforme indicado abaixo:</p><pre><code class="language-jsx">function Welcome(props) {
  return &lt;h1&gt;Olá, {props.name}&lt;/h1&gt;;
}

const element = &lt;Welcome name="Faisal Arkan" /&gt;;
ReactDOM.render(
  element,
  document.getElementById('root')
);</code></pre><p><code>name="Faisal Arkan"</code> será o valor passado por {props.name} a partir da função Welcome(props) e retornará um componente que recebeu o valor <code>name="Faisal Arkan"</code>. Depois disso, o React renderizará o elemento em html.</p><h3 id="outras-maneiras-de-se-declarar-componentes"><strong>Outras maneiras de se declarar componentes</strong>	</h3><p>Há muitas maneiras de se declarar componentes ao usar o React.js. Há dois tipos de componentes: componentes <strong>sem estado</strong> e componentes <strong>com estado</strong>.</p><h3 id="com-estado"><strong><strong>Com </strong>e<strong>stado</strong></strong></h3><h3 id="componentes-do-tipo-classe"><strong>Componentes do tipo classe</strong></h3><pre><code class="language-jsx">class Cat extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      humor: 'feliz'
    }
  }
  render() {
    return(
      &lt;div&gt;
        &lt;h1&gt;{this.props.name}&lt;/h1&gt;
        &lt;p&gt;
          {this.props.color}
        &lt;/p&gt;
      &lt;/div&gt;
    );
  }
}</code></pre><h3 id="sem-estado">Sem estado</h3><h3 id="componentes-funcionais-arrow-functions-do-es6-"><strong>Componentes funcionais (<em>arrow functions</em> do ES6)</strong></h3><pre><code class="language-jsx">const Cat = props =&gt; {
  return (  
    &lt;div&gt;
      &lt;h1&gt;{props.name}&lt;/h1&gt;
      &lt;p&gt;{props.color}&lt;/p&gt;
    &lt;/div&gt;;
  );
};</code></pre><h3 id="componentes-de-retorno-impl-cito"><strong>Componentes de retorno implícito</strong></h3><pre><code class="language-jsx">const Cat = props =&gt; 
  &lt;div&gt;
    &lt;h1&gt;{props.name}&lt;/h1&gt;
    &lt;p&gt;{props.color}&lt;/p&gt;
  &lt;/div&gt;;</code></pre><p>Os fragmentos são uma forma de renderizar vários elementos sem usar um elemento <em>wrapper</em>. Ao tentar renderizar elementos sem tags envolvendo no JSX, você verá a mensagem de erro "Adjacent JSX elements must be wrapped in an enclosing tag" (Os elementos do JSX adjacentes devem ser envolvidos por tags). Isso ocorre porque, quando o JSX transpila, ele cria elementos com seus nomes de tag correspondentes e não sabe qual nome de tag usar se forem encontrados vários elementos.</p><p>No passado, uma solução frequente para isso era usar uma div <em>wrapper</em> para resolver esse problema. No entanto, a versão 16 do React trouxe a adição do <em>Fragment</em>, que faz com que isso não seja mais necessário.</p><p>O <em>Fragment </em>atua como um <em>wrapper </em>sem adicionar divs desnecessárias ao DOM. Você pode usá-lo diretamente da importação do React ou desconstruí-lo:</p><pre><code class="language-jsx">import React from 'react';

class MyComponent extends React.Component {
  render(){
    return (
      &lt;React.Fragment&gt;
        &lt;div&gt;Eu sou um elemento!&lt;/div&gt;
        &lt;button&gt;Eu sou outro elemento&lt;/button&gt;
      &lt;/React.Fragment&gt;
    );
  }
}

export default MyComponent;</code></pre><pre><code class="language-jsx">// Descontruído
import React, { Component, Fragment } from 'react';

class MyComponent extends Component {
  render(){
    return (
      &lt;Fragment&gt;
        &lt;div&gt;Eu sou um elemento!&lt;/div&gt;
        &lt;button&gt;Eu sou outro elemento&lt;/button&gt;
      &lt;/Fragment&gt;
    );
  }
}

export default MyComponent;</code></pre><p>A versão 16.2 do React simplificou ainda mais esse processo, permitindo que tags JSX vazias fossem interpretadas como fragmentos:</p><pre><code class="language-jsx">return (
  &lt;&gt;
    &lt;div&gt;Eu sou um elemento!&lt;/div&gt;
    &lt;button&gt;Eu sou outro elemento&lt;/button&gt;
  &lt;/&gt;
);</code></pre><h3 id="jsx"><strong><strong>JSX</strong></strong></h3><p>JSX é a abreviação de JavaScript XML.</p><p>JSX é uma expressão que usa instruções HTML válidas no JavaScript. Você pode atribuir essa expressão a uma variável e usá-la em outro lugar. Você pode combinar outras expressões válidas do JavaScript e JSX dentro dessas instruções HTML, colocando-as entre chaves ({}). O Babel também compila o JSX em um objeto do tipo React.createElement().</p><h3 id="express-es-de-uma-linha-e-de-v-rias-linhas"><strong>Expressões de uma linha e de várias linhas</strong></h3><p>As expressões de linha única são simples de usar.</p><pre><code class="language-jsx">const one = &lt;h1&gt;Olá mundo!&lt;/h1&gt;;</code></pre><p>Quando precisar usar várias linhas em uma única expressão do JSX, escreva o código dentro de um único par de parênteses.</p><pre><code class="language-jsx">const two = (
  &lt;ul&gt;
    &lt;li&gt;Uma&lt;/li&gt;
    &lt;li&gt;Duas&lt;/li&gt;
  &lt;/ul&gt;
);</code></pre><h3 id="usando-apenas-tags-html"><strong>Usando apenas tags HTML</strong></h3><pre><code class="language-jsx">const greet = &lt;h1&gt;Olá mundo!&lt;/h1&gt;;</code></pre><h3 id="combina-o-de-express-es-do-javascript-com-tags-html"><strong>Combinação de expressões do JavaScript com tags HTML</strong></h3><p>Podemos usar variáveis do JavaScript entre chaves.</p><pre><code class="language-jsx">const who = "Quincy Larson";
const greet = &lt;h1&gt;Olá {who}!&lt;/h1&gt;;</code></pre><p>Também podemos chamar outras funções do JavaScript entre chaves.</p><pre><code class="language-jsx">function who() {
  return "mundo";
}
const greet = &lt;h1&gt;Olá {who()}!&lt;/h1&gt;;</code></pre><h3 id="somente-uma-nica-tag-pai-permitida"><strong>Somente uma única tag pai é permitida</strong></h3><p>Uma expressão do JSX deve ter apenas uma tag pai. Podemos adicionar várias tags aninhadas somente no elemento pai.</p><pre><code class="language-jsx">// Isso é válido.
const tags = (
  &lt;ul&gt;
    &lt;li&gt;Uma vez&lt;/li&gt;
    &lt;li&gt;Duas vezes&lt;/li&gt;
  &lt;/ul&gt;
);

// Isso não é válido.
const tags = (
  &lt;h1&gt;Olá mundo!&lt;/h1&gt;
  &lt;h3&gt;Esta é minha lista especial:&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;Uma vez&lt;/li&gt;
    &lt;li&gt;Duas vezes&lt;/li&gt;
  &lt;/ul&gt;
);</code></pre><h2 id="exemplo-de-state-no-react"><strong>Exemplo de <em>state</em> no React</strong></h2><p>O <em>state</em> (ou estado, em português) é o local de onde vêm os dados.</p><p>Devemos sempre tentar tornar nosso <em>state</em> o mais simples possível e minimizar o número de componentes com estado. Se tivermos, por exemplo, dez componentes que precisam de dados do estado, devemos criar um componente contêiner que manterá o estado de todos eles.</p><p>O <em>state</em> é, basicamente, como um objeto global que está disponível em todos os lugares em um componente.</p><p>Exemplo de um componente de classe com estado:</p><pre><code class="language-javascript">import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
      
    // Declaramos o estado conforme mostrado abaixo
    
    this.state = {                           
      x: "Este é o x do estado",    
      y: "Este é o y do estado"
    }
  }
  render() {
    return (
      &lt;div&gt;
        &lt;h1&gt;{this.state.x}&lt;/h1&gt;
        &lt;h2&gt;{this.state.y}&lt;/h2&gt;
      &lt;/div&gt;
    );
  }
}
export default App;</code></pre><p>Outro exemplo:</p><pre><code class="language-javascript">import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
    
    // Declaramos o estado conforme mostrado abaixo
    this.state = {                           
      x: "Este é o x do estado",    
      y: "Este é o y do estado"
    }
  }

  render() {
    let x1 = this.state.x;
    let y1 = this.state.y;

    return (
      &lt;div&gt;
        &lt;h1&gt;{x1}&lt;/h1&gt;
        &lt;h2&gt;{y1}&lt;/h2&gt;
      &lt;/div&gt;
    );
  }
}
export default App;</code></pre><h2 id="atualiza-o-do-state"><strong>Atualização do <em>state</em></strong></h2><p>Você pode alterar os dados armazenados no <em>state </em>da sua aplicação usando o método setState do seu componente.</p><pre><code class="language-js">this.setState({ value: 1 });</code></pre><p>Lembre-se de que setState é assíncrono. Portanto, você deve ter cuidado ao usar o estado atual para definir um novo estado. Um bom exemplo disso seria se você quisesse incrementar um valor em seu <em>state</em>.</p><h3 id="o-caminho-errado"><strong>O caminho errado</strong></h3><pre><code class="language-js">this.setState({ value: this.state.value + 1 });</code></pre><p>Isso pode levar a um comportamento inesperado em sua aplicação se o código acima for chamado várias vezes no mesmo ciclo de atualização. Para evitar isso, você pode passar uma função de retorno de chamada do atualizador para setState em vez de um objeto.</p><h3 id="o-caminho-certo"><strong>O caminho certo</strong></h3><pre><code class="language-js">this.setState(prevState =&gt; ({ value: prevState.value + 1 }));</code></pre><h3 id="a-maneira-mais-limpa">A maneira mais limpa</h3><pre><code class="language-text">this.setState(({ value }) =&gt; ({ value: value + 1 }));</code></pre><p>Quando apenas um número limitado de campos no objeto do <em>state</em> é necessário, a destruição do objeto pode ser usada para um código mais limpo.</p><h3 id="exemplo-de-state-x-props-em-react"><strong>Exemplo de <em>state </em>x <em>props </em>em React</strong></h3><p>Quando começamos a trabalhar com componentes do React, frequentemente ouvimos dois termos. Eles são <em>state </em>e <em>props</em>. Portanto, neste artigo, exploraremos o que são esses termos e como eles se diferenciam.</p><h2 id="state-"><strong><em>State</em>:</strong></h2><ul><li>O <em>state</em> é algo que pertence a um componente. Ele pertence a esse componente específico em que é definido. Por exemplo, a idade de uma pessoa é um <em>state</em> (estado) dessa pessoa.</li><li>O <em>state</em> é mutável, mas ele só pode ser alterado pelo componente que o possui. Assim como eu só posso alterar minha idade, ninguém mais pode.</li><li>Você pode alterar um <em>state</em> usando <code>this.setState()</code></li></ul><p>Veja o exemplo abaixo para ter uma ideia de <em>state</em>:</p><h4 id="person-js"><strong><strong><strong><strong>Person.js</strong></strong></strong></strong></h4><pre><code class="language-javascript">  import React from 'react';

  class Person extends React.Component{
    constructor(props) {
      super(props);
      this.state = {
        age:0
      this.incrementAge = this.incrementAge.bind(this)
    }

    incrementAge(){
      this.setState({
        age:this.state.age + 1;
      });
    }

    render(){
      return(
        &lt;div&gt;
          &lt;label&gt;My age is: {this.state.age}&lt;/label&gt;
          &lt;button onClick={this.incrementAge}&gt;Grow me older !!&lt;button&gt;
        &lt;/div&gt;
      );
    }
  }

  export default Person;</code></pre><p>No exemplo acima, <em>age </em>(idade) é o estado do componente Person (pessoa).</p><h2 id="props-"><strong><strong><strong><strong><em>Props</em>:</strong></strong></strong></strong></h2><ul><li>As <em>props </em>são semelhantes aos argumentos de métodos. Elas são passadas para um componente onde esse componente é usado.</li><li>As <em>props</em> são imutáveis. Elas são somente leitura.</li><li>Veja o exemplo abaixo para ter uma ideia das <em>props</em>:</li></ul><h4 id="person-js-1"><strong><strong><strong><strong>Person.js</strong></strong></strong></strong></h4><pre><code class="language-javascript">  import React from 'react';

  class Person extends React.Component{
    render(){
      return(
        &lt;div&gt;
          &lt;label&gt;I am a {this.props.character} person.&lt;/label&gt;
        &lt;/div&gt;
      );
    }
  }

  export default Person;

  const person = &lt;Person character = "good"&gt;&lt;/Person&gt;</code></pre><p>No exemplo acima, <code>const person = &nbsp;&lt;Person character = "good"&gt;&lt;/Person&gt;</code>, estamos passando a <em>prop</em> <code>character = "good"</code> para o componente <code>Person</code>.</p><p>Ele dá como resultado "I am a good person" (em português, "sou uma boa pessoa" – o que é verdade).</p><p>Há muito mais a aprender sobre <em>state </em>e <em>props</em>. Muitas coisas podem ser aprendidas quando você realmente se dedica à programação. Portanto, coloque a mão na massa e saia programando.</p><h2 id="exemplo-de-componente-de-ordem-superior-do-react"><strong>Exemplo de componente de ordem superior do React</strong></h2><p>No React, um <strong>componente de ordem superior </strong>(do inglês, <em>Higher-Order Component</em>, ou HOC) é uma função que recebe um componente e retorna um novo componente. Os programadores usam HOCs para obter a <strong>reutilização da lógica do componente.</strong></p><p>Se você já usou o Redux Connect, já trabalhou com componentes de ordem superior.</p><p>A ideia central é:</p><pre><code class="language-jsx">const EnhancedComponent = enhance(WrappedComponent);</code></pre><p>Onde:</p><ul><li><code>enhance</code> é o componente de ordem superior;</li><li><code>WrappedComponent</code> é o componente que você deseja aprimorar; e</li><li><code>EnhancedComponent</code> é o componente criado.</li></ul><p>Este poderia ser o corpo da HOC aprimorada:</p><pre><code class="language-jsx">function enhance(WrappedComponent) {
  return class extends React.Component {
    render() {
      const extraProp = 'This is an injected prop!';
      return (
        &lt;div className="Wrapper"&gt;
          &lt;WrappedComponent
            {...this.props}
            extraProp={extraProp}
          /&gt;
        &lt;/div&gt;
      );
    }
  }
} </code></pre><p>Nesse caso, <code>enhance</code> retorna uma <strong>classe anônima</strong>,<strong> </strong>que estende <code>React.Component</code>. O novo componente está fazendo três coisas simples:</p><ul><li>Renderizar o <code>WrappedComponent</code> em um elemento div;</li><li>Passar suas próprias <em>props </em>para <code>WrappedComponent</code>; e</li><li>Injetar uma <em>prop </em>adicional a <code>WrappedComponent</code>.</li></ul><p>Os HOCs são apenas um padrão que usa o poder da natureza composicional do React. <strong>Eles adicionam recursos a um componente</strong>. Há muito mais coisas que você pode fazer com eles!</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 criar uma blockchain do zero com Go ]]>
                </title>
                <description>
                    <![CDATA[ Introdução Com a Web 3.0 e a blockchain se tornando mais comuns a cada dia, você sabe o que é blockchain? Você conhece suas vantagens técnicas e seus casos de uso? O objetivo deste tutorial é introduzir a tecnologia de blockchain a partir de uma perspectiva técnica, construindo uma a ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/</link>
                <guid isPermaLink="false">63ec8bb558018c06027beeb0</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Wed, 24 May 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/05/blockchain-bar.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/build-a-blockchain-in-golang-from-scratch/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Build a Blockchain from Scratch with Go</a>
      </p><h2 id="introdu-o"><strong>Introdução</strong></h2><p>Com a Web 3.0 e a <em>blockchain</em> se tornando mais comuns a cada dia, você sabe o que é <em>blockchain</em>? Você conhece suas vantagens técnicas e seus casos de uso?</p><p><strong>O objetivo deste tutorial é introduzir a tecnologia de <em>blockchain</em> a partir de uma perspectiva técnica, construindo uma a partir do zero.</strong></p><p>Esqueça tudo o que você já ouviu sobre <em>blockchain</em> nas redes sociais. Agora, você construirá um sistema de <em>blockchain</em> do zero para entender realmente as entradas e saídas dessa tecnologia distribuída <em>peer-to-peer</em>.</p><p>Depois disso, decida sobre seu futuro e suas vantagens. Alerta de <em>spoiler</em>: você vai se apaixonar pelo software de programação de <em>blockchain</em>.</p><h3 id="como"><strong>Como<strong>?</strong></strong></h3><p>Você seguirá a história de um desenvolvedor de software que está procurando revolucionar seu bar local, através da implementação da tecnologia de <em>blockchain</em> para seu sistema de pagamento.</p><p>Embora a <em>blockchain</em> tenha vários casos de uso inegáveis, no momento, a aplicação número um são os pagamentos. Isto ocorre porque os bancos ainda estão funcionando em uma infraestrutura ineficiente, com 40 anos de idade, alimentada por arquivos CSV e FTP.</p><p>A história vem com muitos fatos engraçados e intrigantes sobre o ecossistema geral da <em>blockchain </em>e diferentes protocolos, como Bitcoin, Ethereum e XRP.</p><h2 id="o-que-voc-vai-criar-aprender-e-fazer-neste-tutorial"><strong>O que você vai criar, aprender e fazer neste tutorial?</strong></h2><ul><li>Você vai configurar um projeto na linguagem Go em sua máquina local sem qualquer experiência prévia com GoLang</li><li>Você gerará e distribuirá seus primeiros <em>tokens </em>(ativos digitais) de <em>blockchain</em>.</li><li>Você desenvolverá um banco de dados controlado pela CLI em Go a partir do zero</li><li>Você descobrirá como poucos usuários possuem direitos em suas aplicações favoritas</li><li>Você descobrirá a principal proposta de valor da <em>blockchain</em></li><li>Você tornará seu BD imutável usando uma função de <em>hash</em> criptográfico segura</li></ul><p>Por isso, vamos começar a nossa história.</p><h2 id="-conhe-a-o-protagonista-andrej-"><strong><strong>⭐</strong> </strong>Conheça o protagonista,<strong><strong> Andrej.</strong></strong></h2><p>Andrej é dono de um bar à noite e desenvolvedor de software de dia em uma pequena cidade eslovaca chamada Bardejov.</p><p>Andrej está cansado de:</p><ul><li><strong>Programação de aplicações sólidas e à moda antiga com PHP/Java/Javascript</strong></li><li>Esquecer quanto dinheiro seus amigos e clientes lhe devem por todos os <em>shots </em>de vodka não pagos de sexta-feira à noite</li><li>Passar tempo coletando e contando moedas, devolvendo troco e geralmente tocando cédulas expostas à COVID-19</li><li>Fazer a manutenção de diferentes fichas plásticas para pebolim, dardos, bilhar e pôquer</li></ul><p>Andrej adoraria:</p><ul><li><strong>Ter um histórico auditável perfeito das atividades</strong> e vendas do bar para tornar seu bar compatível com as normas fiscais</li><li><strong>Transformar seu bar em um ambiente autônomo, eficiente, descentralizado e seguro, no qual seus clientes possam confiar e apenas se divertir</strong></li></ul><p>Seu objetivo é escrever um programa simples e manter todos os saldos de seus clientes de modo virtual.</p><p>Andrej compartilha suas ideias aqui:</p><p>"Cada novo cliente me dará dinheiro, e<strong> eu creditarei para eles uma quantidade equivalente dos meus <em>tokens</em> (moedas/moeda criptográfica)</strong>". Os <em>tokens</em> representarão uma unidade monetária dentro e fora do bar.</p><p>As pessoas usarão os <em>tokens</em> para todas as funcionalidades do bar, desde pagar bebidas, pedir emprestado e emprestar a seus amigos, até jogar tênis de mesa, pôquer e pebolim.</p><p>Ter um bar administrado por meio de <em>tokens</em> gerará um valor imenso para meus clientes. Ao contrário da minha concorrência e de outros bares nesta rua, onde os clientes só gastam dinheiro e conseguem uma ressaca em troca, <strong>os clientes que tiverem fichas do meu bar terão direito de acionistas.</strong></p><p>Semelhante a possuir uma grande parte das ações de uma empresa, como a Apple ou a Microsoft, os clientes que possuem esses <em>tokens</em> de bar poderão decidir como o bar funcionará através de votação e decisão sobre:</p><ul><li>preços das bebidas</li><li>horário de funcionamento</li><li>novas funcionalidades (TV, <em>jukebox</em>...)</li><li>design interior e exterior </li><li>alocação de lucros</li><li>etc.</li></ul><p>Ah, isso será um sonho para programação!</p><p>Chamarei os <em>tokens</em> de: <em>tokens</em> do bar das <em>blockchain</em>, ou <strong>TBB</strong>!"</p><p>Agora que Andrej compartilhou seu sonho, vamos começar.</p><h2 id="sum-rio"><strong>Sumário</strong></h2><ul><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#requisitos">Requisitos</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#configurar-o-projeto">Configurar o projeto</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/ghost/#\30%201-o-banco-de-dados-mvp">01 | O banco de dados MVP</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#\30%202-alterando-o-estado-global-do-bd">02 | Alterando o estado global do BD</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#\30%203-evento-monol-tico-x-transa-o">03 | Evento monolítico x transação</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#\30%204-os-humanos-s-o-gananciosos">04 | Os seres humanos são gananciosos</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#\30%205-por-que-precisamos-da-blockchain">05 | Por que precisamos da blockchain</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#\30%206-o-hash-imut-vel">06 | O hash imutável</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-criar-uma-blockchain-do-zero-com-go/#-pr-ximos-passos">Próximos passos</a></li></ul><h2 id="requisitos"><strong><strong>Requi</strong>sitos</strong></h2><p>Vamos nos aprofundar em nosso tutorial. Recomendo mais de 2 anos de experiência em programação em Java/PHP/Javascript ou outra linguagem similar à Go.</p><p>Se você quiser ter uma boa introdução rápida para começar, <a href="https://www.youtube.com/watch?v=YS4e4q9oBaU">aqui está um curso gratuito</a> (em inglês) que ajudará você.</p><p>Você também pode completar as 17 aulas oficiais de <a href="https://go-tour-br.appspot.com/basics/1">Um tour por Go</a> para se familiarizar com a sintaxe do idioma e conceitos básicos (cerca de 20 minutos).</p><h3 id="por-que-go"><strong>Por que<strong> Go?</strong></strong></h3><p>Porque, assim como a <em>blockchain</em>, é uma tecnologia fantástica para toda a sua carreira de programação. Go é uma linguagem da moda e desenvolvedores de Go são mais bem pagos do que a média das posições em Java/PHP/Javascript.</p><p>Go é otimizado para a arquitetura de CPUs <em>multi-core</em>. Você pode gerar milhares de <em>threads</em> leves (rotinas do Go) sem problemas. É extremamente prático para software paralelos e simultâneos, tais como redes de <em>blockchain</em>.</p><p>Ao escrever seu software em Go, você atinge um nível semelhante ao do C++ em termos de desempenho, desde o início, sem se matar por ter esquecido de liberar a memória.</p><p>Go também compila para binário, o que o torna muito portátil.</p><h2 id="configurar-o-projeto">Configurar o projeto</h2><p>Este artigo tem um repositório dedicado e de código aberto no Github, com o código-fonte completo para que você possa compilar o código e executar o programa em sua própria máquina local.</p><p>Se você ficar preso em qualquer capítulo ou em uma linha de código em particular, crie uma <em>issue </em>no Github do repositório descrevendo seu problema e eu o ajudarei o quanto antes!</p><p>Visite o <a href="https://github.com/web3coach/the-blockchain-bar-newsletter-edition/">repositório no Github</a> e siga as instruções de instalação.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/05/54218031.png" class="kg-image" alt="54218031" width="400" height="400" loading="lazy"></figure><h2 id="01-o-banco-de-dados-mvp"><strong>01 | O banco de dados MVP</strong></h2><p>✍ <code>git checkout c1_genesis_json</code></p><p>Andrej dominou os bancos de dados relacionais em SQL nos anos 90. Ele sabe como fazer modelos de dados avançados e como otimizar as consultas em SQL.</p><p>Chegou a hora de Andrej alcançar a inovação e começar a criar software para a web 3.0.</p><p>Por sorte, após ler o livro "The Lean Startup" na semana passada, Andrej percebe que ainda não deveria projetar demais a solução. Assim, ele escolhe um arquivo JSON simples, mas eficaz, para ser o banco de dados e o <a href="https://pt.wikipedia.org/wiki/Produto_vi%C3%A1vel_m%C3%ADnimo">produto viável mínimo</a>, ou MVP (do inglês, <em>minimum viable product</em>), do bar.</p><p>No início, havia um banco de dados centralizado primitivo.</p><h3 id="resumo-"><strong>Resumo:</strong></h3><p><strong>A <em>blockchain<strong> </strong></em>é um banco de dado</strong>s<strong><strong>.</strong></strong></p><h3 id="usu-rio-1-andrej"><strong><strong>Us</strong>uário<strong> 1, Andrej</strong></strong></h3><p><em>Segunda-feira, 18 de março.</em></p><p>Andrej gera 1 milhão de <em>tokens</em> de utilidade.</p><p>No mundo da <em>blockchain</em>, os <em>tokens</em> são unidades dentro do banco de dados da <em>blockchain</em>. Seu valor real em espécie flutua com base em sua demanda e popularidade.</p><p>Cada <em>blockchain</em> tem um arquivo "<strong>Genesis</strong>". O arquivo "Genesis" é usado para distribuir os primeiros <em>tokens</em> aos participantes iniciais da <em>blockchain</em>.</p><p>Tudo começa com um simples <strong><strong>genesis.json</strong></strong> de teste.</p><p>Andrej cria o arquivo <code>./database/genesis.json</code>, onde ele define que o banco de dados do bar da <em>blockchain</em> terá 1 milhão de <em>tokens</em> e que todas elas pertencerão a Andrej:</p><pre><code class="language-json">{
  "genesis_horario": "2019-03-18T00:00:00.000000000Z",
  "chain_id": "the-blockchain-bar-ledger",
  "saldo": {
      "andrej": 1000000
  }
}
</code></pre><p>Os <em>tokens</em> precisam ter uma "utilidade" real, ou seja, um caso de uso. Os usuários devem ser capazes de pagar com eles a partir do primeiro dia!</p><p>Andrej deve estar em conformidade com as regulamentações da lei. É ilegal a emissão de valores não registrados. Por outro lado, os <em>tokens</em> de utilidade estão em conformidade, então ele imprime e cola imediatamente um novo cartaz com os preços na porta do bar.</p><p>Andrej atribui um valor monetário inicial a seus <em>tokens</em> para poder trocá-los por euro, dólar ou outra moeda.</p><pre><code class="language-json">1 token TBB = 1€

| Item                      	 | Preco   |
| ------------------------------ | ------- |
| Dose de vodka                	 | 1   TBB |
| Suco de laranja           	 | 5   TBB |
| Hamburguer                	 | 2   TBB |
| Garrafa de vodka Crystal Head  | 950 TBB |
</code></pre><p>Andrej também decide <strong>que deve receber 100 </strong><em><strong>tokens</strong></em><strong> por dia</strong> para manter o banco de dados e por ter tido uma ideia tão brilhante e disruptiva.</p><h3 id="fatos-interessantes">Fatos interessantes</h3><blockquote>A primeira genesis Ether (ETH) sobre a blockchain Ethereum foi criada e distribuída aos primeiros investidores e desenvolvedores da mesma maneira que o <em>token</em> de utilidade de Andrej.</blockquote><blockquote>Em 2017, durante um boom das ofertas iniciais de moedas (do inglês, Initial Coin Offers, ou ICO) na rede de blockchain Ethereum, os fundadores do projeto escreveram e apresentaram whitepapers aos investidores. Um whitepaper é um documento técnico que esboça uma questão complexa e uma possível solução, destinada a educar e esclarecer sobre um assunto específico. No mundo da blockchain, um whitepaper serve para delinear as especificações de como essa blockchain em particular será e se comportará uma vez desenvolvida.</blockquote><blockquote>Os projetos de blockchain aumentaram entre 10 e 300 milhões de euros por ideia de <strong>whitepaper</strong>.</blockquote><blockquote>Em troca de dinheiro (o "financiamento" das ICOs), os nomes dos investidores seriam incluídos nos "balanços de genesis" iniciais, semelhante ao que Andrej fez. As esperanças dos investidores em uma ICO estão no fato de que as moedas de genesis subam de valor e que as equipes entreguem a blockchain delineada.</blockquote><blockquote>Naturalmente, nem todas as ideias de whitepaper se concretizam. Investimentos massivos perdidos por ideias pouco claras ou incompletas são a razão pela qual a blockchain recebeu cobertura negativa na mídia através dessas ICOs e para alguns ainda a considerarem uma modinha. A tecnologia da blockchain subjacente, porém, é fantástica e útil, como você aprenderá mais neste artigo. Ela tem sido abusada por alguns maus atores.</blockquote><h3 id="resumo--1"><strong>Resumo:</strong></h3><p>A <em>blockchain </em>é um banco de dados.</p><p>O fornecimento de <em>tokens</em>, o balanço inicial do usuário e as configurações globais da <em>blockchain </em>são definidas em um arquivo genesis.</p><h2 id="02-alterando-o-estado-global-do-bd"><strong><strong>02 | </strong>Alterando o estado global do BD</strong></h2><p>✍ <code>git checkout c2_db_changes_txt</code></p><h2 id="festa-chata"><strong>Festa chata</strong></h2><p><em>Segunda-feira<em>, </em> 25 de <em>Mar</em>ço<em>.</em></em></p><p>Após uma semana de trabalho, as instalações do bar estão prontas para aceitar os <em>tokens</em>. Infelizmente, ninguém aparece. Então, Andrej pede três doses de vodka para si mesmo e escreve as mudanças no banco de dados em um pedaço de papel:</p><pre><code class="language-text">andrej-3;   // 3 doses de vodka
andrej+3;   // tecnicamente comprando de seu próprio bar
andrej+700; // Recompensa por uma semana de trabalho (7x100 por dia)
</code></pre><p>Para evitar recalcular o estado mais recente do saldo de cada cliente, Andrej cria um arquivo <code>./database/state.json</code>, que armazena os saldos em um formato agregado.</p><p>Novo estado do BD:</p><pre><code class="language-json">{
  "saldo": {
      "andrej": 1000700
  }
}
</code></pre><h3 id="b-nus-para-babayaga"><strong>Bônus para BabaYaga</strong></h3><p><em><em>T</em>erça-feira<em>, </em>26 de <em>Mar</em>ço<em>.</em></em></p><p>Para trazer o público até seu bar, Andrej anuncia um bônus exclusivo de 100% para todos que adquirirem os <em>tokens</em> TBB nas próximas 24 horas.</p><p>Ele recebe sua primeira cliente, chamada <strong>BabaYaga</strong>. BabaYaga pré-compra mil euros em <em>tokens</em> e, para comemorar, gasta imediatamente 1 TBB para uma dose de vodka. Ela tem um problema com a bebida.</p><p>Transações do BD escritas em um pedaço de papel:</p><pre><code class="language-text">andrej-2000;   // transfererência para BabaYaga
babayaga+2000; // pré-compra com 100% bônus
babayaga-1;
andrej+1;
andrej+100;    // 1 dia de sol nascendo
</code></pre><p>Novo estado do BD:</p><pre><code class="language-json">{
  "saldo": {
      "andrej": 998801,
      "babayaga": 1999
  }
}
</code></pre><h3 id="fatos-interessantes-1">Fatos interessantes</h3><blockquote>Os projetos de ICO (ofertas iniciais de moedas, baseadas em whitepaper) de blockhain frequentemente distribuem os <em>tokens</em> de genesis com diferentes bônus, dependendo de quantos deles você compra e de você ter feito isso rapidamente. As equipes oferecem, em média, 10-40% de bônus aos "participantes" iniciais.</blockquote><blockquote>A palavra "investidor" é evitada, de modo que os reguladores legais não considerarão os <em>tokens</em> como um valor não registrado. Os projetos argumentariam que seu produto principal, <em>tokens</em> de blockchain, funcionam como "milhas de vôo ou pontos de fidelidade".</blockquote><blockquote>Os "participantes", mais tarde, fazem até 1.000% de seu investimento vendendo ao público através de um intercâmbio vários meses depois.</blockquote><h3 id="resumo--2"><strong>Resumo:</strong></h3><p>A <em>blockchain</em> é um banco de dados.</p><p>O fornecimento de <em>tokens</em>, o balanço inicial do usuário e as configurações globais da <em>blockchain</em>, você define em um arquivo Genesis.</p><p><strong>Os balanços de Genesis indicam qual era o estado original da <em>blockchain</em> e nunca são atualizados depois.</strong></p><p><strong>As mudanças de estado do banco de dados são chamadas de transações (TX).</strong></p><h2 id="03-evento-monol-tico-x-transa-o"><strong><strong>03 | </strong></strong>Evento monolítico x transação</h2><p>✍ <code>git checkout c3_state_blockchain_component</code></p><p>Os desenvolvedores acostumados à arquitetura de fornecimento de eventos devem ter reconhecido imediatamente os princípios familiares por trás das transações. Eles estão corretos.</p><p>As transações das <em>blockchain </em>representam uma série de eventos. O banco de dados é um estado final agregado, calculado após a repetição de todas as transações em uma sequência específica</p><h3 id="andrej-programando"><strong>Andrej programando</strong></h3><p><em>Terça-feira à noite, 26 de março.</em></p><p>É uma noite relaxante de terça-feira para Andrej. Comemorando seu primeiro cliente, ele decide jogar <a href="https://www.youtube.com/watch?v=Ff4VIghrTMg&amp;feature=youtu.be&amp;t=516">Starcraft</a> e limpar sua máquina de desenvolvimento local, removendo algumas fotos antigas.</p><p>Infelizmente, ele pressionou prematuramente a tecla Enter ao digitar um comando de comando de remoção no terminal, <code>sudo rm -rf /</code>. Xiiii!</p><p>Todos os seus arquivos, incluindo os arquivos <code>genesis.json</code> e <code>state.json</code> do bar, desapareceram.</p><p>Andrej, sendo um desenvolvedor sênior, gritou repetidamente algumas palavras bem alto por alguns segundos, mas não entrou em pânico!</p><p>Embora ele não tivesse um back-up, ele tinha algo melhor – um pedaço de papel com todas as transações do banco de dados. A única coisa que ele precisa fazer é reproduzir todas as transações uma a uma e o estado de seu banco de dados será recuperado.</p><p>Impressionado com as vantagens da arquitetura baseada em eventos, ele decide ampliar sua solução de banco de dados MVP. Cada atividade do bar, como a compra individual de bebidas, DEVE ser registrada dentro do banco de dados da <em>blockchain</em>.</p><p>Cada <strong>consumidor</strong> será representado no BD utilizando uma estrutura de <strong>conta</strong>:</p><pre><code class="language-go">type Conta string
</code></pre><p>Cada <strong>Transação</strong> (TX – uma mudança de banco de dados) terá os quatro atributos seguintes: <strong>de, para, valor</strong> e <strong>dados</strong>.</p><p>O atributo de <strong>dados</strong> com um valor possível (<strong>recompensa</strong>) captura o bônus de Andrej por inventar a <em>blockchain</em> e aumenta artificialmente a oferta total inicial de <em>tokens</em> TBB (inflação).</p><pre><code class="language-go">type Tx struct {
   De  Account `json:"de"`
   Para    Account `json:"para"`
   Valor uint    `json:"valor"`
   Dado  string  `json:"dado"`
}

func (t Tx) IsReward() bool {
   return t.Dado == "recompensa"
}
</code></pre><p>O<strong> BD de Genesis</strong> permanecerá com um arquivo JSON:</p><pre><code class="language-json">{
  "genesis_horario": "2019-03-18T00:00:00.000000000Z",
  "chain_id": "the-blockchain-bar-ledger",
  "saldo": {
      "andrej": 1000000
  }
}</code></pre><p>Todas as transações, previamente escritas em um pedaço de papel, serão armazenadas em um banco de dados local de arquivos de texto chamado <strong>tx.db</strong>, serializado em formato JSON e separado por caracteres de quebra de linha:</p><pre><code class="language-json">{"de":"andrej","para":"andrej","valor":3,"dado":""}
{"de":"andrej","para":"andrej","valor":700,"dado":"recompensa"}
{"de":"andrej","para":"babayaga","valor":2000,"dado":""}
{"de":"andrej","para":"andrej","valor":100,"dado":"recompensa"}
{"de":"babayaga","para":"andrej","valor":1,"dado":""}
</code></pre><p>O componente mais crucial do banco de dados, que encapsula toda a lógica comercial será o <strong>Estado</strong>:</p><pre><code class="language-go">type Estado struct {
   Saldos   map[Conta]uint
   txMempool []Tx

   dbFile *os.File
}
</code></pre><p>A estrutura do Estado saberá sobre todos os saldos de usuários, quem transferiu os <em>tokens</em> TBB para quem e quantos foram transferidos.</p><p>É construído através da leitura do saldo inicial de usuários do arquivo <code>genesis.json</code>:</p><pre><code class="language-go">func NewStateFromDisk() (*Estado, error) {
   // Obter o diretorio de trabalho atual
   cwd, err := os.Getwd()
   if err != nil {
      return nil, err
   }

   genFilePath := filepath.Join(cwd, "database", "genesis.json")
   gen, err := loadGenesis(genFilePath)
   if err != nil {
      return nil, err
   }

   saldo := make(map[Conta]uint)
   for conta, saldo := range gen.Saldos {
      saldos[conta] = saldo
   }
</code></pre><p>Em seguida, os balanços do Estado de <code>genesis</code> são atualizados através da reprodução sequencial de todos os eventos do banco de dados do tx.db:</p><pre><code class="language-go">   txDbFilePath := filepath.Join(cwd, "database", "tx.db")
   f, err := os.OpenFile(txDbFilePath, os.O_APPEND|os.O_RDWR, 0600)
   if err != nil {
      return nil, err
   }

   scanner := bufio.NewScanner(f)
   estado := &amp;Estado{saldos, make([]Tx, 0), f}

   // Iterar sobre cada linha do arquivo tx.db
   for scanner.Scan() {
      if err := scanner.Err(); err != nil {
         return nil, err
      }

      // Converter TX codificado pelo JSON em um objeto (estrutura)
      var tx Tx
      json.Unmarshal(scanner.Bytes(), &amp;tx)

      // Reconstruir o Estado (saldos de usuários),
      // como uma série de eventos
      if err := estado.apply(tx); err != nil {
         return nil, err
      }
   }

   return estado, nil
}
</code></pre><p>O componente Estado é responsável por:</p><ul><li><strong>Adicionar</strong> novas transações ao <strong>Mempool</strong></li><li><strong>Validar</strong> as transações contra o Estado atual (saldo suficiente do remetente)</li><li><strong>Mudar</strong> o estado</li><li>Salvar transações <strong>persistentes</strong> em disco</li><li><strong>Calcular os</strong> saldos de contas através da repetição de todas as transações desde Genesis em uma seqüência</li></ul><p><strong>Adicionar</strong> novas transações ao Mempool:</p><pre><code class="language-go">func (s *Estado) Add(tx Tx) error {
   if err := s.apply(tx); err != nil {
      return err
   }

   s.txMempool = append(s.txMempool, tx)

   return nil
}
</code></pre><p><strong>Persistir</strong> as transações em disco:</p><pre><code class="language-go">func (s *Estado) Persist() error {
   // Faça uma cópia do mempool porque o s.txMempool será modificado
   // no laço abaixo
   mempool := make([]Tx, len(s.txMempool))
   copy(mempool, s.txMempool)

   for i := 0; i &lt; len(mempool); i++ {
      txJson, err := json.Marshal(mempool[i])
      if err != nil {
         return err
      }

      if _, err = s.dbFile.Write(append(txJson, '\n')); err != nil {
         return err
      }

      // Remover o TX escrito em um arquivo do mempool
      s.txMempool = s.txMempool[1:]
   }

   return nil
}</code></pre><p><strong>Mudar</strong>, <strong>validar</strong> o estado:</p><pre><code class="language-go">func (s *Estado) apply(tx Tx) error {
   if tx.IsReward() {
      s.Saldos[tx.To] += tx.Valor
      return nil
   }

   if tx.Valor &gt; s.Saldos[tx.De] {
      return fmt.Errorf("saldo insuficiente")
   }

   s.Saldos[tx.De] -= tx.Valor
   s.Saldos[tx.Para] += tx.Valor

   return nil
}
</code></pre><h3 id="construir-uma-interface-de-linha-de-comando-cli-">Construir uma interface de linha de comando<strong><strong> (CLI)</strong></strong></h3><p><em>Terça-feira à noite, 26 de março.</em></p><p>Andrej quer ter uma maneira conveniente de adicionar novas transações ao seu banco de dados e listar os últimos saldos de seus clientes. Como os programas Go compilam para binário, ele faz uma CLI para seu programa.</p><p>A maneira mais fácil de desenvolver programas baseados em CLI em Go é usando a biblioteca de terceiros <code>github.com/spf13/cobra</code>.</p><p>Andrej inicializa o gerenciador de dependências de Go para seu projeto, chamado <code>go modules</code>:</p><p>✍ <code>cd $GOPATH/src/github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition</code></p><p>✍ <code>go mod init github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition</code></p><p>O comando <code>Go modules</code> buscará automaticamente qualquer biblioteca a que você se referir dentro de seus arquivos Go.</p><p>Andrej cria um diretório chamado <code>cmd</code>, com um subdiretório <code>tbb</code>:</p><p>✍<code>mkdir -p ./cmd/tbb</code></p><p>Dentro, ele cria um arquivo <code>main.go</code>, servindo como o ponto de entrada da CLI do programa:</p><pre><code class="language-go">package main

import (
    "github.com/spf13/cobra"
    "os"
    "fmt"
)

func main() {
    var tbbCmd = &amp;cobra.Command{
        Use:   "tbb",
        Short: "The Blockchain Bar CLI",
        Run: func(cmd *cobra.Command, args []string) {
        },
    }
    
    err := tbbCmd.Execute()
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}
</code></pre><p>Os programas Go são compilados usando o comando <code>install</code>:<br><br>✍ <code>go install ./cmd/tbb/...</code></p><pre><code class="language-text">go: finding github.com/spf13/cobra v1.0.0
go: downloading github.com/spf13/cobra v1.0.0
go: extracting github.com/spf13/cobra v1.0.0</code></pre><p>O Go detectará as bibliotecas ausentes e as buscará automaticamente antes de compilar o programa. Dependendo de seu $GOPATH, o programa resultante será salvo na pasta <code>$GOPATH/bin</code>.</p><p>✍<code>echo $GOPATH</code></p><pre><code class="language-text">/home/web3coach/go</code></pre><p>✍<code>which tbb</code></p><pre><code class="language-text">/home/web3coach/go/bin/tbb</code></pre><p>Você pode executar o tbb de seu terminal agora, mas ele não fará nada porque a função <code>Run</code> dentro do arquivo <code>main.go</code> está vazia.</p><p>A primeira coisa que Andrej precisa é de suporte de versão para seu programa <code>tbb</code> da CLI.</p><p>Ao lado do arquivo <code>main.go</code>, ele cria um comando <code>version.go</code>:</p><pre><code class="language-go">package main

import (
    "fmt"
    "github.com/spf13/cobra"
)

const Major = "0"
const Minor = "1"
const Fix = "0"
const Verbal = "Adicionar TX e listar saldos"

var versionCmd = &amp;cobra.Command{
    Use:   "versão",
    Short: "Descreve a versão.",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Versão: %s.%s.%s-beta %s", Major, Minor, Fix, Verbal)
    },
}
</code></pre><p>Ele compila o programa e o executa:<br>✍ <code>go install ./cmd/tbb/...</code><br>✍ <code>tbb version</code></p><p><code>Versão: 0.1.0-beta Adicionar TX e listar saldos</code></p><p>Perfeito.</p><p>De modo idêntico ao arquivo <code>version.go</code>, ele cria um arquivo <code>balance.go</code>:</p><pre><code class="language-go">func saldosCmd() *cobra.Command {
    var saldosCmd = &amp;cobra.Command{
        Use:   "saldos",
        Short: "Interage com saldos (lista...).",
        PreRunE: func(cmd *cobra.Command, args []string) error {
            return incorrectUsageErr()
        },
        Run: func(cmd *cobra.Command, args []string) {
        },
    }

    saldosCmd.AddCommand(saldosListaCmd)

    return saldosCmd
}
</code></pre><p>O comando <code>saldos</code> será responsável por carregar o último estado do BD e imprimi-lo para a saída padrão:</p><pre><code class="language-go">var saldosListaCmd = &amp;cobra.Command{
    Use:   "list",
    Short: "Lista todos os saldos.",
    Run: func(cmd *cobra.Command, args []string) {
        estado, err := database.NewStateFromDisk()
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }
        defer estado.Close()

        fmt.Println("Saldos das contas:")
        fmt.Println("__________________")
        fmt.Println("")
        for conta, saldo := range estado.Saldos {
            fmt.Println(fmt.Sprintf("%s: %d", conta, saldo))
        }
    },
}
</code></pre><p>Andrej verifica se o comando funciona como esperado. Ele deve imprimir os saldos exatos definidos no arquivo Genesis porque o arquivo <code>tx.db</code> ainda está vazio.</p><p>✍ <code>go install ./cmd/tbb/...</code></p><p>✍ <code>tbb saldos list</code></p><pre><code>Saldos das contas:
__________________
andrej: 1000000
</code></pre><p>Funciona bem! Agora, ele só precisa de um comando para registrar a atividade do bar.</p><p>Andrej cria o comando <code>./cmd/tbb/tx.go</code>:</p><pre><code class="language-go">func txCmd() *cobra.Command {
    var txsCmd = &amp;cobra.Command{
        Use:   "tx",
        Short: "Interage com as txs (adicionar...).",
        PreRunE: func(cmd *cobra.Command, args []string) error {
            return incorrectUsageErr()
        },
        Run: func(cmd *cobra.Command, args []string) {
        },
    }

    txsCmd.AddCommand(txAddCmd())

    return txsCmd
}
</code></pre><p>O comando <code>tbb tx add</code> utiliza a função <code>Estado.Adicionar(tx)</code> para a persistência dos eventos do bar no sistema de arquivos:</p><pre><code class="language-go">func txAddCmd() *cobra.Command {
    var cmd = &amp;cobra.Command{
        Use:   "add",
        Short: "Adiciona novo TX ao banco de dados.",
        Run: func(cmd *cobra.Command, args []string) {
            de, _ := cmd.Flags().GetString(flagDe)
            para, _ := cmd.Flags().GetString(flagPara)
            valor, _ := cmd.Flags().GetUint(flagValor)

            deConta := database.NewAccount(de)
            paraConta := database.NewAccount(para)
            
            tx := database.NewTx(deConta, paraConta, valor, "")

            estado, err := database.NewStateFromDisk()
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }
            
            // Deferir ao final da execução dessa função
            // A executação da seguinte declaração (fechar o arquivo DB com todos os TXs)
            defer estado.Close()
            
            // Adicionar o TX a um array em memória (pool)
            err = estado.Add(tx)
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }
            
            // Limpa os TXs do mempool para o disco
            err = estado.Persist()
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            fmt.Println("TX adicionada com sucesso ao ledger.")
        },
    }
</code></pre><p>O comando <code>tbb tx add</code> tem 3 <em>flags </em>obrigatórias: <code>--de</code>, <code>--para</code> e <code>--valor</code>.</p><pre><code class="language-go">cmd.Flags().String(flagDe, "", "De que conta enviar os tokens")
cmd.MarkFlagRequired(flagDe)

cmd.Flags().String(flagPara, "", "Para que conta enviar os tokens")
cmd.MarkFlagRequired(flagPara)

cmd.Flags().Uint(flagValor, 0, "Quantos tokens enviar")
cmd.MarkFlagRequired(flagValor)

return cmd
</code></pre><p>A CLI está feita!</p><p>Andrej migra todas as transações do papel para o novo BD:</p><p>✍ <code>tbb tx add --de=andrej --para=andrej --valor=3</code></p><p>✍<code>tbb tx add --de=andrej --para=andrej --valor=700</code></p><p>✍<code>tbb tx add --de=babayaga --para=andrej --valor=2000</code></p><p>✍<code>tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa</code></p><p>✍<code>tbb tx add --de=babayaga --para=andrej --valor=1</code></p><p>Leia todos os TXs a partir do disco e calcule o estado mais recente:</p><p>✍ <code>tbb saldos list</code></p><pre><code>Saldos das contas:
__________________
andrej: 998801
babayaga: 1999
</code></pre><p>Dados do bar restaurados com sucesso! Ufa! Que noite!</p><h3 id="sobre-a-biblioteca-cobra-cli"><strong>Sobre a biblioteca Cobra CLI</strong></h3><p>O bom da biblioteca Cobra para a programação da CLI está nas características adicionais que ela traz consigo. Por exemplo, agora, você pode executar o comando <code>tbb help</code> e imprimirá todos os subcomandos registrados na TBB com instruções sobre como usá-los.</p><pre><code class="language-bash"> tbb help

The Blockchain Bar CLI

Usage:
  tbb [flags]
  tbb [command]

Available Commands:
  balances    Interage com balanços (list...).
  help        Ajuda sobre qualquer comando
  tx          Interage com txs (add...).
  version     Descreve a versão.

Flags:
  -h, --help   ajuda para tbb

Use "tbb [comando] --help" para mais informações sobre um comando.
</code></pre><h3 id="fatos-interessantes-2">Fatos interessantes</h3><blockquote>A perda acidental de dados dos clientes é normal no mundo corporativo nos dias de hoje. A blockchain corrige isso descentralizando o armazenamento de dados.</blockquote><blockquote>Há um truque que Andrej introduziu no programa ao pular a verificação de saldos para os TX marcados como "recompensas". <strong>Bitcoin e Ethereum funcionam da mesma forma.</strong> O saldo da Conta que <strong>minerou um bloco</strong> aumenta do nada como um assunto de inflação total de fornecimento dos tokens, que afeta toda a cadeia. O fornecimento total de bitcoins é limitado a 21M BTC. Você aprenderá mais sobre "mineração" e "blocos" posteriormente.</blockquote><blockquote>Os componentes <strong>State</strong> (estado) e <strong>Mempool</strong> não são exclusivos deste programa. Andrej escolheu os nomes e designs para combinar com um modelo simplificado da <a href="https://github.com/ethereum/go-ethereum/blob/7b32d2a47017570c44cd7f8a83612a29656c9857/core/tx_pool.go#L211">go-Ethereum</a>, para que você tenha uma ideia do código fonte central do Ethereum.</blockquote><h3 id="resumo--3"><strong>Resumo:</strong></h3><p>A <em>blockchain</em> é um banco de dados.</p><p>O fornecimento de <em>tokens</em>, os balanços iniciais dos usuários e as configurações globais da <em>blockchain </em>são definidos em um arquivo Genesis.</p><p>Os balanços de Genesis indicam qual era o estado original da <em>blockchain </em>e nunca são atualizados depois.</p><p>As mudanças de estado do banco de dados são chamadas Transações (TX).</p><p><strong>As transações são eventos ao estilo antigo, que representam ações dentro do sistema.</strong></p><h3 id="-c-digo-de-estudo"><strong><strong>⚒ </strong></strong>Código de estudo</h3><p>Commit: <a href="https://github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition/commit/5d4b0b6a001e616109da732fdaf7094f1e1acf85">5d4b0b</a></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/05/unlock_blockchain_components_state.png" class="kg-image" alt="unlock_blockchain_components_state" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/05/unlock_blockchain_components_state.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/05/unlock_blockchain_components_state.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/05/unlock_blockchain_components_state.png 1600w" sizes="(min-width: 720px) 720px" width="1600" height="2500" loading="lazy"></figure><p>Vamos falar sobre a ganância.</p><h2 id="04-os-humanos-s-o-gananciosos"><strong><strong>04 | </strong></strong>Os humanos são gananciosos</h2><p>✍ <code>git checkout c4_caesar_transfer</code></p><h3 id="a-gan-ncia-t-pica-dos-neg-cios"><strong>A ganância típica dos negócios</strong></h3><p>Quarta-feira, 27 de março.</p><p>BabaYaga investiu um pouco demais. Ela esqueceu que o pagamento do aluguel do apartamento estava chegando e, agora, não tem o dinheiro. BabaYaga chama o proprietário de seu apartamento, <strong>César</strong>.</p><p><strong>BabaYaga</strong>: Ei, César, sinto muito, mas não tenho dinheiro para pagar o aluguel este mês...</p><p><strong><strong>Caesar:</strong></strong> Por que não?</p><p><strong><strong>BabaYaga:</strong></strong> O ICO do Blockchain Bar ofereceu um bônus enorme e eu comprei 2000 <em>tokens</em> no valor de apenas mil euros. Foi um grande negócio!</p><p><strong><strong>C</strong>é<strong>sar:</strong></strong> Do que você está falando? O que é um ICO? O que são <em>tokens</em>? Você pode me pagar de algum outro modo?</p><p><strong><strong>BabaYaga:</strong></strong> Ah, outra vez, não. Eu posso dar mil <em>tokens</em> TBB, que valem mil euros, e você pode usá-los no bar para pagar suas bebidas! Deixe-me ligar para o dono do bar, Andrej, e fazer a transferência!</p><p><strong><strong>C</strong>é<strong>sar:</strong></strong> Muito bem... eu vou aceitar.</p><p>Andrej realiza a transferência, <strong>mas decide cobrar mais 50 </strong><em><strong>tokens</strong></em><strong> de TBB por ter de fazer os procedimentos.</strong> Ele não quer, MAS os acionistas do bar que investiram nele há alguns anos estão forçando-o a gerar lucro o mais rápido possível.</p><p>BabaYaga não vai ter problemas com esta taxa relativamente pequena, muito provavelmente, diz Andrej a si mesmo. No final, somente ele tem o acesso ao BD.</p><p>// Pagamento do aluguel</p><p>✍<code>tbb tx add --de=babayaga --para=cesar --valor=1000</code></p><p>// Cobrança de taxa oculta</p><p>✍ <code>tbb tx add --de=babayaga --para=andrej --valor=50</code></p><p>// Nova recompensa por mais um dia de manutenção do BD</p><p>✍ <code>tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa</code></p><h3 id="fatos-interessantes-3">Fatos interessantes</h3><blockquote>O caso de uso número um da blockchain é o bancário. Muitos projetos de blockchain visam otimizar o câmbio nacional e internacional de dinheiro através de diferentes canais de moedas (XRP).</blockquote><blockquote>Outros projetos enfocam a liberdade e a identidade própria (SSI, do inglês, Self-sovereign identity) – um movimento digital que reconhece que um indivíduo deve possuir e controlar sua identidade e dinheiro sem as autoridades administrativas intervenientes ou outros intermediários centralizados. A SSI permite que as pessoas interajam no mundo digital com a mesma liberdade e capacidade de confiança que interagem no mundo off-line. (Bitcoin / Ethereum)</blockquote><blockquote>Aqui estão alguns fatos interessantes que explicam o porquê de a blockchain ser um ajuste perfeito para substituir a infraestrutura bancária atual de seu banco.</blockquote><blockquote>O bom dos <em>tokens</em> é sua fungibilidade - ou seja, sua capacidade de serem comercializados, com cada unidade sendo tão utilizável quanto a próxima. A realização de uma transferência de conta para conta pode ser feita simplesmente mudando o estado do banco de dados. As moedas criptográficas são negociáveis 24 horas por dia, 7 dias por semana.</blockquote><blockquote>Você não pode negociar ações diretamente. Você precisa passar por um corretor que participa de uma porcentagem da transação total como taxa (1-3% a 7% do lucro médio anual).</blockquote><blockquote>Uma transferência bancária internacional leva entre 3-10 dias úteis e pode custar até 5% do valor transferido! Se você estiver enviando $10.000, poderá ter que pagar até $500. A tecnologia por trás disso nos últimos 40 anos? FTP + arquivos CSV.</blockquote><blockquote>Você acha que o mercado de ações é justo? Os bancos, índices e ações são altamente centralizados e controlados por governos e grupos privados de Wall Street. O mercado livre? Wall Street controla o quanto os preços podem saltar/cair em um único dia.</blockquote><blockquote>Como exemplo, Wall Street suspendeu a negociação do "Índice S&amp;P 500" após uma queda de 7% para proteger seus investidores e fundos especulativos de perder dinheiro das pessoas que venderam suas ações durante março de 2020, após as notícias da COVID. Posteriormente, o FED imprimiu trilhões de dólares para eles mesmos para apoiar o preço das ações. Se você é um desenvolvedor que gosta de economizar dinheiro e evitar dívidas, suas economias acabarão perdendo valor de um dia para o outro por uma porcentagem ainda desconhecida.</blockquote><blockquote>Muitos países estão entrando em rendimentos negativos, um território inexplorado com consequências desconhecidas. O que isto significa? Em breve você terá que pagar ao banco para manter suas economias. Inflação no seu melhor. Você está sendo obrigado a gastar seu dinheiro para apoiar um sistema que você não controla.</blockquote><h3 id="-c-digo-de-estudo-1"><strong><strong>⚒ </strong></strong>Código de estudo</h3><p>Commit: <a href="https://github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition/commit/00d6ede25b1e54ceb30c0a0314ef99a612db01de">00d6ed</a></p><h2 id="05-por-que-precisamos-da-blockchain"><strong><strong>05 | </strong></strong>Por que precisamos da blockchain</h2><p>✍ <code>git checkout c5_broken_trust</code></p><h3 id="babayaga-busca-justi-a"><strong>BabaYaga busca justiça</strong></h3><p>Quinta-feira, 28 de março.</p><p><strong>BabaYaga</strong> entra no bar para seu aniversário.</p><p><strong><strong>BabaYaga:</strong></strong> Ei, Andrej! Hoje é meu aniversário! Traga-me sua garrafa mais cara!</p><p><strong><strong>Andrej:</strong></strong> Feliz aniversário! Aqui está: Vodka Crystal Head. Mas você precisa comprar um <em>token</em> TBB adicional. A garrafa custa 950 <em>tokens</em>, e seu saldo é de 949.</p><p><strong><strong>BabaYaga:</strong></strong> O quê?! Meu saldo deveria ser de 999 TBB!</p><p><strong><strong>Andrej:</strong></strong> A transferência de fundos para César que você solicitou na semana passada custou 50 <em>tokens</em>.</p><p><strong><strong>BabaYaga:</strong></strong> Isto é inaceitável! Eu nunca concordaria com uma taxa tão alta. Você não pode fazer isto, Andrej. Confiei em seu sistema, mas você é tão pouco confiável quanto qualquer outro proprietário de empresa. As coisas devem mudar!</p><p><strong><strong>Andrej:</strong></strong> Muito bem, veja. Você é minha cliente mais fiel e eu não queria cobrar de você, mas meus acionistas me obrigaram.</p><p><strong>Deixe-me reprogramar meu sistema e torná-lo completamente transparente e descentralizado.</strong> Afinal, se todos fossem capazes de interagir com o bar sem passar por mim, isso melhoraria significativamente a eficiência do bar e equilibraria o nível de confiança!</p><ul><li>Pedir bebidas levaria segundos ao invés de minutos</li><li>Os clientes que esqueceram suas carteiras em casa poderiam pedir emprestado ou emprestar <em>tokens</em> um ao outro</li><li>Eu não teria que me preocupar em perder os dados dos clientes (novamente), pois todos teriam uma cópia dos mesmos</li><li><strong>O banco de dados seria imutável, portanto, uma vez que todos estivessem de acordo sobre um estado específico, ninguém mais poderia mudá-lo ou modificar maliciosamente a história.</strong> A imutabilidade também ajudaria nas auditorias fiscais anuais!</li><li>Se os acionistas quisessem introduzir novas taxas ou aumentar as taxas atuais, todos os envolvidos no sistema de blockchain notariam e teriam que concordar com ele. Os usuários e proprietários de empresas teriam até mesmo que se engajar em algum sistema de governança descentralizada em conjunto, baseado na votação, provavelmente. Em caso de desacordo, os usuários se afastam com todos os seus dados!</li></ul><p><strong><strong>BabaYaga:</strong></strong> Bem, certamente soa bem, mas será que isso é mesmo possível?</p><p><strong><strong>Andrej:</strong></strong> Sim, eu acho que sim. Com um pouco de <strong>hashing</strong>, <strong>listas vinculadas</strong>, <strong>estrutura de dados imutável</strong>, <strong>replicação</strong> <strong>distribuída</strong> e <strong>criptografia assimétrica!</strong></p><p><strong><strong>BabaYaga:</strong></strong> Não faço ideia do que você acabou de dizer, mas vá em frente e faça suas nerdices, Andrej!</p><h3 id="fatos-interessantes-4">Fatos interessantes</h3><blockquote>Os mineradores Bitcoin e Ethereum também recebem recompensas a cada 15 minutos, aproximadamente, por executar os servidores da blockchain (os nós) e validar as transações.</blockquote><blockquote>A cada 15 minutos, um minerador de Bitcoins recebe 12,5 BTC ($100 mil no momento em que este artigo foi escrito) para cobrir o custo de seus servidores + obter algum lucro.</blockquote><blockquote>A rede das Bitcoins consome tanta eletricidade quanto o país inteiro da Áustria. Ela é responsável por 0,29% do consumo anual de eletricidade mundial.</blockquote><blockquote>Anualmente, ela consome 76,84 TWh, produzindo 36,50 Mt de rastro de carbono de CO2 (Nova Zelândia). <a href="https://digiconomist.net/bitcoin-energy-consumption">Fonte</a>.</blockquote><blockquote>Por quê? Você aprenderá mais tarde onde você programará um algoritmo de mineração de Bitcoin a partir do zero!</blockquote><blockquote>Observação: nosso algoritmo consumirá um pouco menos de eletricidade🙂</blockquote><h3 id="resumo--4"><strong>Resumo:</strong></h3><p>O software, quando não é de código aberto, dá acesso centralizado aos dados privados, o que permite que apenas um punhado de pessoas tenha muito poder. Os usuários não têm escolha, e os acionistas estão no negócio para ganhar dinheiro.</p><p><strong>Os desenvolvedores da <em>blockchain</em> visam desenvolver protocolos onde os empresários e usuários das aplicações se sinergizem em uma relação transparente e auditável. As especificações do sistema da blockchain devem ser bem definidas desde o início e só devem mudar se seus usuários o apoiarem.</strong></p><p>A <em>blockchain</em> é um banco de dados. O fornecimento de <em>tokens</em>, os saldos iniciais de usuários e as configurações globais da <em>blockchain </em>são definidos em um arquivo Genesis. Os balanços Genesis indicam qual era o estado original da <em>blockchain </em>e nunca são atualizados posteriormente.</p><p>As mudanças de estado do banco de dados são chamadas Transações (TX). Transações são eventos à moda antiga que representam ações dentro do sistema.</p><h3 id="-c-digo-de-estudo-2">⚒<strong> Código de estudo</strong></h3><p>Commit: <a href="https://github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition/commit/64204512f2173eb3f3e136e7e2674a2c456d351f">642045</a></p><h2 id="06-o-hash-imut-vel"><strong><strong>06 | </strong></strong>O hash imutável</h2><p>✍ <code>git checkout c6_immutable_hash</code></p><p><em>A dificuldade técnica começa com esta seção! Os conceitos só vão ficar mais desafiadores mas, ao mesmo tempo, muito empolgantes. Apertem os cintos 😀</em></p><h3 id="como-programar-um-banco-de-dados-imut-vel"><strong>Como programar um banco de dados imutável?</strong></h3><p><em>Sexta-feira, 29 de março.</em></p><p>Se Andrej quer descobrir como programar um BD imutável, ele tem que entender porque outros sistemas de banco de dados são mutáveis por padrão.</p><p>Ele decide analisar uma tabela poderosa do BD do MySQL:</p><pre><code class="language-text">| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 998951  |
| 2  | BabaYaga | 949     | 
| 3  | Caesar   | 1000    |</code></pre><p>No BD MySQL, qualquer pessoa com acesso e uma razão suficientemente boa pode realizar uma atualização de tabela como, por exemplo:</p><pre><code class="language-mysql">UPDATE saldo_usuario SET saldo = saldo + 100 WHERE id &gt; 1
</code></pre><p>A atualização de valores através de diferentes linhas é possível porque as linhas da tabela são independentes, mutáveis e o estado mais recente não é aparente.</p><p>Qual é a última mudança no BD? A última coluna mudou? Qual é a última linha inserida? Como Andrej pode saber qual linha foi apagada recentemente? Se as linhas e o estado da tabela estivessem firmemente unidos, dependentes, a atualização da linha 1 geraria uma tabela completamente nova e diferente. Andrej conseguiria sua imutabilidade.</p><blockquote>Como você pode saber se algum byte em um banco de dados mudou?</blockquote><h3 id="imutabilidade-via-fun-es-de-hash"><strong>Imutabilidade via funções de hash</strong></h3><p><em>Hashing </em>é o processo de tomar uma string de entrada de comprimento arbitrário e produzir uma string de hash de comprimento fixo. Qualquer mudança na entrada, resultará em um <em>hash</em> novo e diferente.</p><pre><code class="language-go">package main

import (
	"crypto/sha256"
	"fmt"
)

func main() {
	saldosHash := sha256.Sum256([]byte("| 1 | Andrej | 99895 |"))
	fmt.Printf("%x\n", saldosHash)
	// Output: 6a04bd8e2...f70a3902374f21e089ae7cc3b200751
	
	// Mudar o saldo de 99895 -&gt; 99896
	
	saldosHashDiff := sha256.Sum256([]byte("| 1 | Andrej | 99896 |"))
	fmt.Printf("%x\n", saldosHashDiff)
	// Saída: d04279207...ec6d280f6c7b3e2285758030292d5e1
}
</code></pre><p>Experimente: <a href="https://play.golang.org/p/FTPUa7IhOCE">https://play.golang.org/p/FTPUa7IhOCE</a></p><p>Andrej também requer algum nível de segurança para seu banco de dados. Por isso, ele decide por uma <strong>função de hash criptográfico</strong> com as seguintes propriedades:</p><ul><li>é <a href="https://en.wikipedia.org/wiki/Deterministic_algorithm">determinista</a> – a mesma mensagem resulta sempre no mesmo hash</li><li>é rápida para calcular o valor de hash para qualquer mensagem dada</li><li>é inviável gerar uma mensagem a partir de seu valor hash, exceto tentando todas as mensagens possíveis</li><li>uma pequena mudança em uma mensagem deve mudar o valor de hash tão extensivamente que o novo valor de hash pareça não estar relacionado com o antigo valor de hash</li><li>é <a href="https://en.wikipedia.org/wiki/Computational_complexity_theory#Intractability">inviável</a> (texto em inglês) encontrar duas mensagens diferentes com o mesmo valor de hash</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/05/hash_fruit.png" class="kg-image" alt="hash_fruit" width="298" height="200" loading="lazy"><figcaption>Exemplo de hashing com frutas – <a href="https://twitter.com/cybergibbons/status/1203291585473110016">fonte da imagem</a></figcaption></figure><h3 id="implementando-o-hashing-do-conte-do-do-bd"><strong>Implementando o hashing do conteúdo do BD</strong></h3><p><em>Sábado à noite, 30 de março.</em></p><p>Andrej modifica a função <code>Persist()</code> para devolver um novo hash de conteúdo, <code>Snapshot</code>, toda vez que uma nova transação é persistida.</p><pre><code class="language-go">type Snapshot [32]byte
</code></pre><p>O Snapshot é produzido por esta nova função de <em>hashing </em>seguro sha256:</p><pre><code class="language-go">func (s *Estado) doSnapshot() error {
   // Lê novamente todo o arquivo desde o primeiro byte
   _, err := s.dbFile.Seek(0, 0)
   if err != nil {
      return err
   }

   txsData, err := ioutil.ReadAll(s.dbFile)
   if err != nil {
      return err
   }
   s.snapshot = sha256.Sum256(txsData)

   return nil
}
</code></pre><p>A função <code>doSnapshot()</code> é chamada pela função <code>Persist()</code> modificada. Quando uma nova transação é escrita no arquivo <code>tx.db</code>, <code>Persist()</code> faz o <em>hash</em> de todo o conteúdo do arquivo e retorna seu <em>hash</em> uma "impressão digital" de 32 bytes.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/05/persist_function.png" class="kg-image" alt="persist_function" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/05/persist_function.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/05/persist_function.png 800w" sizes="(min-width: 720px) 720px" width="800" height="690" loading="lazy"><figcaption>Persist() faz o hash do arquivo tx.db inteiro</figcaption></figure><p>A partir deste momento, todos podem se referir com 100% de confiança e segurança a qualquer estado particular do banco de dados (conjunto de dados) com um <em>hash</em> específico.</p><h3 id="-hora-da-pr-tica"><strong><strong>⚓</strong>Hora da prática</strong></h3><p><strong>1/4</strong> Execute o comando da lista de saldos e verifique se os balanços estão de acordo.</p><p>✍ <code>tbb saldos list</code></p><pre><code class="language-text">Saldos das contas em 7d4a360f465d...

| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 999251  |
| 2  | BabaYaga | 949     | 
| 3  | Cesar    | 1000    |</code></pre><p><strong><strong>2/4</strong></strong> Remova as 2 últimas filas de <code>./database/tx.db</code> e verifique novamente os saldos.</p><p>✍ <code>tbb saldos list</code></p><pre><code class="language-bash">Saldos das contas 841770dcd3...

| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 999051  |
| 2  | BabaYaga | 949     | 
| 3  | Cesar    | 1000    |
</code></pre><p><strong><strong>3/4</strong></strong> Recompense Andrej pelos últimos 2 dias (de 28 a 30 de março):</p><p>Transação de recompensa 1:</p><p>✍ <code>tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa</code></p><pre><code class="language-bash">Persisting new TX to disk:
       {"de":"andrej","para":"andrej","valor":100,"dado":"recompensa"}
       
New DB Snapshot: ff2470c7043f5a34169b5dd38921ba6825b03b3facb83e426
TX persistida com sucesso no ledger.
</code></pre><p>Transação de recompensa 2:</p><p>✍ <code>tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa</code></p><pre><code class="language-bash">Persisting new TX to disk:
       {"from":"andrej","to":"andrej","value":100,"data":"reward"}
       
New DB Snapshot: 7d4a360f468b837b662816bcdc52c1869f99327d53ab4a9ca
TX persistida com sucesso no ledger.
</code></pre><p><strong><strong>4/4</strong></strong> Execute o comando da lista de saldos de tbb e garanta que os balanços e o hash do snapshot sejam os mesmos do início.</p><p>✍ <code>tbb saldos list</code></p><pre><code class="language-bash">Saldos das contas em 7d4a360f465d...

| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 999251  |
| 2  | BabaYaga | 949     | 
| 3  | Cesar    | 1000    |
</code></pre><p><strong>Pronto!</strong></p><p>Como a função criptográfica de hash <strong>sha256</strong> produz a mesma saída (dadas as mesmas entradas, a <code>tx.db</code> atual e 2x <code>tbb tx add</code>), se você seguir os passos exatos em seu próprio computador, você gerará exatamente o mesmo estado e hashes do banco de dados!</p><h3 id="resumo--5"><strong>Resumo:</strong></h3><p>O software fechado com acesso centralizado aos dados privados coloca apenas algumas poucas pessoas na posição de poder. Os usuários não têm escolha, e os acionistas estão no negócio para ganhar dinheiro.</p><p>Os desenvolvedores da <em>blockchain </em>visam desenvolver protocolos onde os empresários e usuários das aplicações se sinergizem em uma relação transparente e auditável. As especificações da <em>blockchain</em> devem ser bem definidas desde o início e só devem mudar se seus usuários o apoiarem.</p><p>A<em> blockchain </em>é um banco de dados <strong>imutável</strong>. O fornecimento de <em>tokens</em>, os saldos iniciais de usuários e as configurações globais da <em>blockchain </em>que você define em um arquivo Genesis. Os balanços Genesis indicam qual era o estado original da <em>blockchain </em>e nunca são atualizados depois.</p><p>As mudanças de estado do banco de dados são chamadas Transações (TX). Transações são eventos à moda antiga que representam ações dentro do sistema.</p><p><strong>O conteúdo do banco de dados é passado por uma função de hash criptográfico segura. Os participantes da <em>blockchain </em>usam o hash resultante para referenciar um estado específico do banco de dados.</strong></p><h3 id="-c-digo-de-estudo-3"><strong><strong>⚒ </strong>Código de estudo</strong></h3><p>Commit: <a href="https://github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition/commit/b99e5191b19bc076b98a3869289e4788d0a4a77b">b99e51</a></p><h2 id="-pr-ximos-passos"><strong><strong><strong><strong>⭐</strong></strong></strong>Próximos passos</strong></h2><p>Você terminou os primeiros capítulos! Parabéns!</p><p>█▒▒▒▒▒▒▒▒▒ 10%</p><p>Este, porém, foi apenas um aquecimento rápido. A <em>blockchain </em>é uma tecnologia muito desafiadora e extensa. Você precisaria de um livro inteiro explicando como construir o sistema completo e todos os seus componentes a partir do zero. Por isso, escrevi um.</p><p>Você pode continuar lendo o próximo capítulo gratuito no eBook com minha versão da <em>newsletter </em>"The Blockchain Way of Programming".</p><p><strong>07 | O Modelo de programação da blockchain</strong></p><ul><li>Melhorando o desempenho de um BD imutável</li><li>Batch + Hash + Lista vinculadas ⇒ Blocos</li><li>Migrando de TX.db para BLOCKS.db</li></ul><p><strong>Aprendizagem</strong>: você redesenha e refatora seu banco de dados MVP e o transforma em uma arquitetura de <em>blockchain</em>.</p><h3 id="continua-o-do-tutorial-https-web3-coach-book">Continuação do tutorial<strong><strong><strong><strong>: </strong></strong></strong></strong><a href="https://web3.coach/#book" rel="nofollow"><strong><strong><strong><strong>https://web3.coach#book</strong></strong></strong></strong></a></h3><p>Obrigado por leitura!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial sobre chaves em objetos do JavaScript – como usar um par chave-valor em JS ]]>
                </title>
                <description>
                    <![CDATA[ Você pode agrupar os dados relacionados em uma única estrutura de dados usando um objeto JavaScript, como este: const mesa = {    altura: "1 metro e 20",    peso: "30 libras",    cor: "marrom",    material: "madeira",  }; Um objeto ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/tutorial-sobre-chaves-em-objetos-do-javascript-como-usar-um-par-chave-valor-em-js/</link>
                <guid isPermaLink="false">63c5429791baea05fef7057a</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Thu, 09 Mar 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/objects.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/javascript-object-keys-tutorial-how-to-use-a-js-key-value-pair/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">JavaScript Object Keys Tutorial – How to Use a JS Key-Value Pair</a>
      </p><p>Você pode agrupar os dados relacionados em uma única estrutura de dados usando um objeto JavaScript, como este:</p><pre><code class="language-javascript">const mesa = {
   altura: "1 metro e 20",
   peso: "30 libras",
   cor: "marrom",
   material: "madeira",
 };
</code></pre><p>Um objeto contém propriedades ou pares chave-valor. O objeto <code>mesa</code> acima tem quatro propriedades. Cada propriedade tem um nome, também chamado de chave, e um valor correspondente.</p><p>Por exemplo, a chave <code>altura</code> tem o valor de "1 metro e 20". Juntos, a chave e o valor formam uma única propriedade.</p><pre><code class="language-javascript">altura: "1 metro e 20",
</code></pre><p>O objeto <code>mesa</code> contém dados sobre uma mesa. Na verdade, essa é uma razão pela qual você usaria um objeto do JavaScript: para armazenar dados. Também é simples recuperar os dados que você armazena em um objeto. Esses aspectos tornam os objetos muito úteis.</p><p>Este artigo trará informações sobre os objetos em JavaScript:</p><ul><li>como criar um objeto</li><li>como armazenar dados em um objeto</li><li>e recuperar dados a partir dele.</li></ul><p>Comecemos pela criação de um objeto.</p><h2 id="como-criar-um-objeto-em-javascript"><strong>Como criar um objeto em JavaScript</strong></h2><p>Vou criar um objeto chamado pizza abaixo e acrescentar a ele pares chave-valor.</p><pre><code class="language-javascript">const pizza = {
   sabor: "queijo",
   molho: "marinara",
   tamanho: "pequeno"
};
</code></pre><p>As chaves estão à esquerda dos dois pontos <code>:</code> e os valores estão à direita dele. Cada par chave-valor é uma <code>propriedade</code>. Há três propriedades nesse exemplo:</p><ul><li>A &nbsp;chave <strong>sabor </strong>tem um valor "<strong>queijo</strong>". </li><li>A chave <strong>molho </strong>tem um valor "<strong><strong>marinara</strong></strong>". </li><li>A chave <strong>tamanho </strong>tem um valor "<strong>pequeno</strong>". </li></ul><p>Cada propriedade é separada por uma vírgula. As propriedades, juntas, ficam cercadas por chaves <code>{}</code>.</p><p>Essa é a sintaxe básica do objeto. Há, porém, algumas regras a serem seguidas ao criar objetos em JavaScript.</p><h2 id="chaves-de-objetos-em-javascript"><strong>Chaves de objetos em JavaScript</strong></h2><p>Cada chave em seu objeto do JavaScript deve ser uma string, símbolo ou número.</p><p>Veja com atenção o exemplo abaixo. Os nomes de chave <code>1</code> e <code>2</code> são, na verdade, transformados em strings.</p><pre><code class="language-javascript">const carrinhoCompras = {
   1: "maçã",
   2: "laranja"
};
</code></pre><p>É uma diferença deixada clara quando se imprime o objeto.</p><pre><code class="language-javascript">console.log(carrinhoCompras);
//Resultado: { '1': 'maçã', '2': 'laranja' }
</code></pre><p>Há outra regra a ter em mente sobre nomes de chaves: se seu nome de chave tiver espaços, você precisa deixá-lo entre aspas.</p><p>Dê uma olhada no objeto <code>desenvolvedor</code> abaixo. Observe o último nome de chave, "nome do projeto atual". Esse nome de chave contém espaços. Portanto, eu o deixei entre aspas.</p><pre><code class="language-javascript">const desenvolvedor = {
   nome: "Phil",
   idade: 21,
   desenvolvedorBackend: true,
   linguagens: ["Python", "JavaScript", "Java", "C++"],
   "nome do projeto atual": "O Incrível aplicativo"
};
</code></pre><h2 id="valores-de-objetos-em-javascript"><strong>Valores de objetos em JavaScript</strong></h2><p>Um valor, por outro lado, pode ser qualquer tipo de dado, incluindo um array, número ou booleano. Os valores no exemplo acima contêm estes tipos: string, inteiro, booleano e array.</p><p>Você pode até usar uma função como um valor. Nesse caso, ela é conhecida como método. <code>sons()</code>, no objeto abaixo, é um exemplo.</p><pre><code class="language-javascript">const animal = {
   tipo: "gato",
   nome: "gatinho",
   sons() { console.log("miau miau") }
};
</code></pre><p>Agora, vamos supor que você queira adicionar ou excluir um par chave-valor ou que, simplesmente, você queira recuperar o valor de um objeto.</p><p>Você pode fazer essas coisas usando a notação de ponto ou de colchetes, sobre as quais falaremos em seguida.</p><h2 id="como-a-nota-o-de-ponto-e-a-nota-o-de-colchetes-funcionam-em-javascript"><strong>Como a notação de ponto e a notação de colchetes funcionam em JavaScript</strong></h2><p>A notação de ponto e a notação de colchetes são duas maneiras de acessar e usar as propriedades de um objeto. É provável que você use a notação de pontos com mais frequência. Por isso, vamos começar com ela.</p><h3 id="como-adicionar-um-par-chave-valor-com-nota-o-de-pontos-em-javascript"><strong>Como adicionar um par chave-valor com notação de pontos em JavaScript</strong></h3><p>Vou criar um objeto vazio abaixo, chamado <code>livro</code>.</p><pre><code class="language-javascript">const livro = {};
</code></pre><p>Para adicionar um par chave-valor usando a notação de ponto, use a sintaxe:</p><p>nomeDoObjeto.nomeDaChave = valor</p><p>Esse é o código para adicionar a chave (autor) e o valor ("Jane Smith") ao objeto <code>livro</code>:</p><pre><code class="language-javascript">livro.autor = "Jane Smith";
</code></pre><p>Aqui está um desdobramento do código acima:</p><ul><li><code>livro</code> é o nome do objeto</li><li>. (ponto)</li><li><code>autor</code> é o nome da chave</li><li>= (igual)</li><li>"Jane Smith" é o valor</li></ul><p>Quando eu imprimir o objeto <code>livro</code>, verei o novo par chave-valor adicionado.</p><pre><code class="language-javascript">console.log(livro);
//Resultado: { autor: 'Jane Smith' }
</code></pre><p>Vou adicionar outro par chave-valor ao objeto <code>livro</code>.</p><pre><code class="language-javascript">livro.anoPublicacao = 2006;
</code></pre><p>O objeto <code>livro</code> tem agora duas propriedades.</p><pre><code class="language-javascript">console.log(livro);
//Resultado: { autor: 'Jane Smith', anoPublicacao: 2006 }
</code></pre><h3 id="como-acessar-dados-em-um-objeto-javascript-usando-a-nota-o-de-ponto"><strong>Como acessar dados em um objeto JavaScript usando a notação de ponto</strong></h3><p>Você também pode usar a notação de ponto em uma chave para <em>acessar</em> o valor relacionado.</p><p>Considere este objeto <code>jogadorBasquete</code>.</p><pre><code class="language-javascript">const jogadorBasquete = {
   nome: "James",
   mediaPontosPorJogo: 20,
   altura: "1,90 m",
   posicao: "ala-armador"
};
</code></pre><p>Digamos que você queira recuperar o valor "ala-armador". Esta é a sintaxe a ser usada:</p><p>nomeDoObjeto.nomeDaChave</p><p>Vamos utilizar essa sintaxe para obter e imprimir o valor "ala-armador".</p><pre><code class="language-javascript">console.log(jogadorBasquete.posicao);
//Resultado: ala-armador
</code></pre><p>Aqui está um desdobramento do código acima:</p><ul><li>jogadorBasquete é o nome do objeto</li><li>. &nbsp;(ponto)</li><li>posicao é o nome da chave</li></ul><p>Aqui temos outro exemplo:</p><pre><code class="language-javascript">console.log(jogadorBasquete.nome);
//Resultado: James
</code></pre><h3 id="como-excluir-um-par-chave-valor-em-javascript"><strong>Como excluir um par chave-valor em JavaScript</strong></h3><p>Para excluir um par chave-valor, use o operador de exclusão. Esta é a sintaxe:</p><p><code>delete nomeObjeto.nomeChave</code></p><p>Assim, para apagar a chave <code>altura</code> e seu valor do objeto jogadorBasquete, você escreveria este código:</p><pre><code class="language-javascript">delete jogadorBasquete.altura;
</code></pre><p>Como resultado, o objeto jogadorBasquete agora tem três pares chave-valor.</p><pre><code class="language-javascript">console.log(jogadorBasquete);
//Resultado: { nome: 'James', mediaPontosPorJogo: 20, posicao: 'ala-armador' }
</code></pre><p>É provável que você use frequentemente a notação de ponto, embora haja certos requisitos a serem observados.</p><p>Ao utilizar a notação de ponto, os nomes de chave não podem conter espaços, hifens, ou começar com um número.</p><p>Por exemplo, digamos que eu tente adicionar uma chave que contém espaços usando a notação de pontos. Vou receber um erro.</p><pre><code class="language-javascript">jogadorBasquete.porcentagem de acertos = "75%";
//Resulta em um erro</code></pre><p>Portanto, a notação de pontos não funcionará em todas as situações. É por isso que existe outra opção: a notação de colchetes.</p><h3 id="como-adicionar-um-par-chave-valor-usando-nota-o-de-colchetes-em-javascript"><strong>Como adicionar um par chave-valor usando notação de colchetes em JavaScript</strong></h3><p>Assim como a notação de ponto, você pode usar a notação de colchetes para adicionar um par chave-valor a um objeto.</p><p>A notação de colchetes oferece mais flexibilidade do que a notação de ponto. Isso porque os nomes de chave podem incluir espaços e hifens, podendo também começar com números.</p><p>Vou criar um objeto <code>funcionario</code> abaixo.</p><pre><code class="language-javascript">const funcionario = {};
</code></pre><p>Agora, quero adicionar um par chave-valor usando a notação de colchetes. Esta é a sintaxe:</p><p>nomeDoObjeto["nomeDaChave"] = valor</p><p>Então, é assim que eu adicionaria a chave (<code>ocupação</code>) e o valor (<code>vendas</code>) ao objeto do funcionário:</p><pre><code class="language-javascript">funcionario["ocupação"] = "vendas";
</code></pre><p>Aqui está um desdobramento do código acima:</p><ul><li><code>funcionario</code> é o nome do objeto</li><li><code>"ocupação"</code> é o nome da chave</li><li>= (igual)</li><li><code>"vendas"</code> é o valor</li></ul><p>Abaixo estão mais alguns exemplos que utilizam a flexibilidade da notação de colchetes para adicionar uma variedade de pares chave-valor.</p><pre><code class="language-javascript">//Acrescentar um nome de chave com várias palavras
funcionario["viaja frequentemente"] = true;
 
//Adicionar um nome de chave que inclui um hífen
funcionario["Primeiro-território"] = "Chicago";
 
//Adicionar um nome de chave que comece com um número
funcionario["25"] = "total de clientes";
</code></pre><p>Quando imprimo o objeto funcionário, esta é a aparência:</p><pre><code class="language-javascript">{
  '25': 'total de clientes',
  ocupacao: 'vendas',
  'viaja frequentemente': true,
  'Primeiro-território': 'Chicago'
}
</code></pre><p>Com essa informação em mente, podemos adicionar a chave <code>"porcentagem de acertos"</code> ao objeto <code>jogadorBasquete</code> abaixo.</p><pre><code class="language-javascript">const jogadorBasquete = {
   nome: "James",
   mediaPontosPorJogo: 20,
   altura: "1,90 m",
   posicao: "ala-armador"
};
</code></pre><p>Você deve se lembrar que a notação de ponto nos deixou com um erro quando tentamos adicionar uma chave que incluía espaços.</p><pre><code class="language-javascript">jogadorBasquete.porcentagem de acertos = "75%";
//Resulta em um erro</code></pre><p>A notação de colchetes, no entanto, evita esses erros, como você pode ver aqui:</p><pre><code class="language-javascript">jogadorBasquete["porcentagem de acertos"] = "75%";
</code></pre><p>Este é o resultado quando eu imprimo o objeto:</p><pre><code class="language-javascript">{
  nome: 'James',
  mediaPontosPorJogo: 20,
  altura: '1,90 m',
  posicao: 'ala-armador',
  'porcentagem de acertos': '75%'
}
</code></pre><h3 id="como-acessar-dados-em-um-objeto-do-javascript-usando-a-nota-o-de-colchetes"><strong>Como acessar dados em um objeto do JavaScript usando a notação de colchetes</strong></h3><p>Você também pode usar a notação de parênteses em uma chave para <em>acessar</em> o valor relacionado.</p><p>Vamos recordar do objeto <code>animal</code> do início do artigo.</p><pre><code class="language-javascript">const animal = {
   tipo: "gato",
   nome: "gatinho",
   sons() { console.log("miau miau") }
};
</code></pre><p>Vamos obter o valor associado à chave <code>nome</code>. Para isso, envolva o nome da chave entre aspas e coloque-a entre colchetes. Esta é a sintaxe:</p><p>nomeDoObjeto["nomeDaChave"]</p><p>Aqui está o código que você escreveria com a notação de colchetes: </p><p><code>animal["nome"];</code></p><p>Este é um desdobramento do código acima:</p><ul><li><code>animal</code> é o nome do objeto</li><li><code>["nome"]</code> é o nome da chave entre colchetes</li></ul><p>Aqui está outro exemplo.</p><pre><code class="language-javascript">console.log(animal["sons"]());

//Resultado: 
miau miau
undefined
</code></pre><p>Note que sons() é um método. Por isso, acrescentei os parênteses no final para invocá-lo.</p><p>É assim que você invocaria um método usando a notação de ponto.</p><pre><code class="language-javascript">console.log(animal.sons());

//Resultado: 
miau miau
undefined
</code></pre><h2 id="m-todos-em-objetos-do-javascript"><strong>Métodos em objetos do JavaScript</strong></h2><p>Agora, você já sabe como acessar propriedades específicas. Se, no entanto, você quiser <em>todas</em> as chaves ou <em>todos</em> os valores de um objeto, como faria?</p><p>Há dois métodos que darão as informações de que você precisa.</p><pre><code class="language-javascript">const corredor = {
   nome: "Jessica",
   idade: 20,
   milhasPorSemana: 40,
   corrida: "maratona"
};
</code></pre><p>Use o método <code>Object.keys()</code> para recuperar todos os nomes de chave de um objeto.</p><p>Esta é a sintaxe:</p><p><code>Object.keys(nomeDoObjeto)</code></p><p>Podemos usar esse método no objeto <code>corredor</code> acima.</p><pre><code class="language-javascript">Object.keys(corredor);
</code></pre><p>Se você imprimir o resultado, receberá um array das chaves do objeto.</p><pre><code class="language-javascript">console.log(Object.keys(corredor));
//Resultado: [ 'nome', 'idade', 'milhasPorSemana', 'corrida' ]
</code></pre><p>Do mesmo modo, você pode usar o método <code>Object.values()</code> para obter todos os valores de um objeto. Esta é a sintaxe:</p><p><code>Object.values(nomeObjeto)</code></p><p>Agora, vamos obter todos os valores do objeto <code>corredor</code>.</p><pre><code class="language-javascript">console.log(Object.values(corredor));
//Resultado: [ 'Jessica', 20, 40, 'maratona' ]
</code></pre><p>Tratamos de muitas coisas. Aqui está um resumo das principais ideias:</p><h3 id="objetos"><strong>Objetos</strong></h3><ul><li>Usamos objetos para armazenar dados como propriedades (pares chave-valor).</li><li>Os nomes de chave devem ser strings, símbolos ou números.</li><li>Os valores podem ser de qualquer tipo.</li></ul><h3 id="acessar-propriedades-dos-objetos"><strong>Acessar propriedades dos objetos</strong></h3><ul><li>Notação de pontos: <code>nomeDoObjeto.nomeDaChave</code></li><li>Notação de colchetes: <code>nomeDoObjeto["nomeDaChave"]</code></li></ul><h3 id="excluir-uma-propriedade"><strong>Excluir uma propriedade</strong></h3><ul><li><code>delete nomeDoObjeto.nomeDaChave</code><br></li></ul><p>Você pode fazer muito com objetos. Agora, você conhece o básico para tirar proveito desse tipo de dados poderoso do JavaScript.</p><p><em>A autora escreve sobre aprender a programar e sobre as melhores maneiras de se fazer isso em seu blog, <a href="http://amymhaddad.com/">amymhaddad.com</a>. Ela também usar o Twitter para falar sobre programação, aprendizagem e produtividade: <a href="https://twitter.com/amymhaddad">@amymhaddad</a>.</em></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Desempenho com o VS Code – como otimizar o Visual Studio Code e escolher as "melhores" extensões ]]>
                </title>
                <description>
                    <![CDATA[  O Visual Studio Code (VS Code) foi projetado para ser leve. Ele tem um conjunto restrito de características principais. Você pode, porém, adicionar características extras através de extensões. O desempenho, contudo, será inevitavelmente afetado à medida que sua coleção de extensões crescer. Você avalia o desempenho de uma extensão ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/desempenho-com-o-vs-code-como-otimizar-o-visual-studio-code-e-escolher-as-melhores-extensoes/</link>
                <guid isPermaLink="false">63bbbe0aad276e05ed7572d8</guid>
                
                    <category>
                        <![CDATA[ VS Code ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Sun, 05 Mar 2023 22:30:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/banner-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/optimize-vscode-performance-best-extensions/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">VS Code Performance – How to Optimize Visual Studio Code and Choose the "Best" Extensions</a>
      </p><p></p><p>O Visual Studio Code (VS Code) foi projetado para ser leve. Ele tem um conjunto restrito de características principais. Você pode, porém, adicionar características extras através de extensões.</p><p>O desempenho, contudo, será inevitavelmente afetado à medida que sua coleção de extensões crescer.</p><p>Você avalia o desempenho de uma extensão antes de instalá-la? O que você faz se a inicialização do VS Code crescer? Devido à ausência de pessoas escrevendo sobre esse tópico, acho que as pessoas não sabem.</p><p>Neste artigo, vou explicar os fatores que afetam o desempenho de uma extensão. Também vou avaliar o desempenho de algumas extensões populares. Em seguida, vou delinear como você pode verificar o desempenho de seu conjunto de extensões existente e dar algumas dicas gerais de desempenho.</p><h2 id="requisitos-m-nimos-de-hardware-e-software"><strong>Requisitos mínimos de hardware e software</strong></h2><p>Antes de entrarmos em extensões, vamos falar brevemente sobre quais são os requisitos mínimos para executar o VS Code.</p><p>Um computador comprado nos últimos anos com especificações modestas deve ser capaz de executar o VS Code sem nenhum problema.</p><h3 id="hardware"><strong><strong>Hardware</strong></strong></h3><p>O hardware mínimo que eu recomendo é:</p><ul><li>Processador de 1.6 GHz ou mais rápido;</li><li>Pelo menos 1 GB of RAM;</li><li>Pelo menos 200 MB de espaço em disco.</li></ul><h3 id="sistemas-operacionais"><strong>Sistemas operacionais</strong></h3><p>O VS Code foi testado nos seguintes sistemas operacionais:</p><ul><li>Mac OS X Yosemite e posteriores.</li><li>Windows 7 (com .NET Framework 4.5.2), 8.0, 8.1 e 10 (32-bit e 64-bit).</li><li>Linux (Debian): Ubuntu Desktop 14.04, Debian 7.</li><li>Linux (Red Hat): Red Hat Enterprise Linux 7, CentOS 7, Fedora 23.</li></ul><h3 id="a-comunidade-n-o-oficial-cria-para-o-raspberry-pi-e-para-chromebooks"><strong>A comunidade não oficial cria para o Raspberry Pi e para Chromebooks</strong></h3><p>Jay Rodgers lançou um projeto <em>open-source</em> que realiza <a href="http://code.headmelted.com/"><em>builds </em>frequentes do VS Code para Raspberry Pi e Chromebooks.</a></p><blockquote><em>Tenho mantido o projeto há alguns anos e ele se expandiu do fornecimento de binários para Pi para o fornecimento de suporte e ferramentas para colocar o VS Code em funcionamento em dispositivos ARM de baixo custo que, de outro modo, não o suportariam como os Chromebooks (que agora constituem cerca de 60% dos dispositivos nas escolas).</em></blockquote><p>Se você quiser experimentar por si mesmo, pode seguir as instruções que ele apresentou. Ele tem trabalhado muito para tornar o processo o mais simples possível.</p><h2 id="nem-todas-as-extens-es-s-o-criadas-do-mesmo-modo"><strong>Nem todas as extensões são criadas do mesmo modo</strong></h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/blind-judgment.jpg" class="kg-image" alt="blind-judgment" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/blind-judgment.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/blind-judgment.jpg 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/blind-judgment.jpg 1490w" sizes="(min-width: 720px) 720px" width="1490" height="1118" loading="lazy"><figcaption>Edição de "Blindfolded Lady Justice", criada por <a href="https://unsplash.com/@tingeyinjurylawfirm?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Tingey Injury Law Firm</a> e extraída do <a href="https://unsplash.com/s/photos/equal?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p><br>As extensões são carregadas e descarregadas sob diferentes condições. O autor da extensão decide isso. Isto é especificado através de<em> eventos de ativação</em>, que discutiremos mais tarde.</p><p>Não há feedback no editor indicando se uma extensão está ativa ou não. Então, como sabemos quando uma extensão está ativa?</p><p>A maioria das extensões é escrita em TypeScript, mas elas também podem ser escritas em JavaScript. As extensões podem incluir módulos do Node como dependências.</p><p>Você pode agrupar e minificar seus arquivos fonte em um único arquivo, se desejar. A <a href="https://code.visualstudio.com/api/working-with-extensions/bundling-extension">documentação do </a><a href="https://code.visualstudio.com/api/working-with-extensions/bundling-extension">VS Code</a> recomenda fazer isso para melhorar os tempos de carregamento, mas muitas extensões não o fazem. Essas escolhas afetam o desempenho.</p><p>As extensões são, em sua maioria, projetos de código aberto escritos por desenvolvedores. A qualidade do código pode variar. A manutenção do código vai variar, com certeza.</p><p>As extensões escritas pela Microsoft não são imunes a essas deficiências, mas são as menos propensas a sofrer com elas.</p><h2 id="crit-rios-para-selecionar-uma-extens-o"><strong>Critérios para selecionar uma extensão</strong></h2><p>A maioria das listas de extensões fala sobre as características interessantes, mas pouco mais além disso. Quando algo é muito bom, fale-me um pouco também sobre o contexto, certo?</p><p>Alguns dos critérios que eu sugiro envolvem a análise do código fonte. Não se deixe adiar por isso. Reunir os fatos-chave leva apenas alguns minutos. Mostrarei como fazer isso!</p><ol><li><strong>O recurso que eu preciso já está disponível no VS Code?</strong></li></ol><p>Eu demonstrei que você não precisa de muitas extensões populares em um artigo <a href="https://roboleary.net/vscode/2020/08/05/dont-need-extensions.html">"VS Code: you don't need that extension"</a> (texto em inglês). Você pode consultar a <a href="https://code.visualstudio.com/Docs">documentação do VS Code</a> para verificar uma característica específica.</p><p><strong>2. A extensão tem as características de que eu preciso?</strong></p><p>Consulte a página da extensão no Visual Studio Marketplace para descobrir isso.</p><p><strong>3. Quando uma extensão está carregada e ativa?</strong></p><p>Discutirei isto em detalhes na seção <a href="https://www.freecodecamp.org/portuguese/news/ghost/#activation-events">Eventos de ativação</a>. Você precisa verificar o <em>package.json </em>do código fonte para descobrir isso com antecedência.</p><p>Você pode executar o comando <strong>Desenvolvedor: Desempenho de Inicialização</strong> para ver os eventos de ativação das extensões instaladas. Eu discuto isso mais adiante na seção <a href="https://www.freecodecamp.org/portuguese/news/ghost/#how-to-audit-performance">Como verificar o desempenho</a>.</p><p><strong>4. Os recursos estão otimizados?</strong></p><p>Você precisa verificar o código fonte para ver se ele usa um <em>bundler</em>. Você pode verificar o <em>package.json</em> para ver se a seção de scripts tem uma etapa de pré-construção para o <em>bundling</em>.</p><p>O arquivo de extensão VSIX é um repositório comprimido de arquivos para o código e a listagem no <em>Marketplace</em>. Os desenvolvedores frequentemente incluem arquivos desnecessários. Há um arquivo <em>.vscodeignore</em> para excluir arquivos.</p><p>O número de arquivos que o VSIX contém tem um impacto sobre o tempo de ativação a frio. O tempo de ativação a frio é a primeira execução da extensão após sua instalação. Ele tende a ser mais lento do que o de outras vezes. Acho que isso ocorre porque o VSIX não está comprimido e está em cache.</p><p>Esta é a aparência da extensão <a href="https://marketplace.visualstudio.com/items?itemName=octref.vetur">Vetur</a> quando você a abre no <a href="https://www.7-zip.org/">7Zip</a>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/vetur-7zip.png" class="kg-image" alt="vetur-7zip" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/vetur-7zip.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/vetur-7zip.png 639w" width="639" height="385" loading="lazy"></figure><p><strong>5. Houve algum problema de desempenho relatado recentemente que não foi resolvido?</strong></p><p>Você pode descobrir isso através da verificação de desempenho da extensão. Você também precisa verificar as <em>issues </em>no repositório do Git.</p><p><strong>6. O código tem testes?</strong></p><p>A extensão vai ser mais suscetível a erros sem testes. Você precisa verificar o código fonte para ver se há testes. </p><p><strong>7. A extensão é mantida ativamente?</strong></p><p>A seção <em>Detalhes do projeto</em> (<em>Project Details</em>, em inglês) na página de extensão dá uma visão geral da atividade do repositório público do Git. Em alguns casos, uma extensão pode estar "concluída" (em inglês, <em>Done</em>). Nesse caso, a manutenção não é uma consideração importante.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/marketplace-maintenance.png" class="kg-image" alt="marketplace-maintenance" width="301" height="313" loading="lazy"></figure><h2 id="eventos-de-ativa-o">Eventos de ativação</h2><p>Eventos de ativação são eventos que acionam a ativação de uma extensão. Eles definem as condições de carregamento e descarregamento de uma extensão.</p><p>O autor de uma extensão declara esses eventos no campo <code>activationEvents</code> do <em>package.json</em> (<a href="https://code.visualstudio.com/api/references/extension-manifest">Manifesto de Extensão</a>, em inglês).</p><p>Há uma variedade de eventos de ativação à sua escolha. Uma extensão pode ouvir muitos eventos de ativação para produzir um escopo mais específico.</p><p>Este é um diagrama de sequência do que acontece quando você lança o VS Code. Ele dá uma ideia da cronologia dos eventos que ocorrem, que afetam quando você pode interagir com o editor e usar certas extensões.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/activation-events-2.svg" class="kg-image" alt="activation-events-2" width="1273" height="539" loading="lazy"></figure><p>Agora, vou passar pelos eventos de ativação mais importantes. Começarei com o escopo mais amplo e continuarei até atingir o escopo mais restrito.</p><h3 id="evento-inicial"><strong>Evento inicial</strong></h3><p>O evento de ativação * ativará uma extensão quando o VS Code for iniciado. Essas extensões estarão <strong>sempre ativas</strong>. Isso impacta o tempo de inicialização do VS Code.</p><pre><code class="language-json">"activationEvents": [
    "*"
]
</code></pre><p>A documentação do VS Code dá os seguintes conselhos:</p><blockquote><em>Para garantir uma ótima experiência do usuário final, use este evento de ativação em sua extensão somente quando nenhuma outra combinação de eventos de ativação funcionar em seu caso de uso.</em></blockquote><p>Na minha opinião, deve haver um caso especial para conceder a uma extensão esse escopo. É preferível usar pelo menos <em>onStartUpFinished</em>.</p><p><strong>Extensões populares com este evento de ativação</strong>: <a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">ES Lint</a> (11 milhões de instalações), <a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer">Live Server</a> (7,4 milhões de instalações), <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLens</a> (6,5 milhões de instalações), <a href="https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify">Beautify</a> (5,4 milhões de &nbsp;instalações), <a href="https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer">Bracket Pair Colorizer</a> (3,6 milhões de instalações), <a href="https://marketplace.visualstudio.com/items?itemName=donjayamanne.githistory">Git History</a> (2,9 milhões de instalações), <a href="https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync">Settings Sync</a> (2 milhões de instalações), <a href="https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow">indent-rainbow</a> (1,1 milhão de instalações).</p><h3 id="evento-onstartupfinished"><strong>Evento <em>onStartupFinished</em> </strong></h3><p>Esta extensão será ativada <strong>algum tempo após o início do</strong> <strong><strong>VS Code</strong></strong>, ou seja, assim como o evento de ativação *, mas não vai desacelerar o início do VS Code.</p><pre><code class="language-json">"activationEvents": [
    "onStartupFinished"
]
</code></pre><p><strong>Extensões populares com este evento de ativação:</strong> <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Prettier</a> (8,5 milhões de instalações).</p><h3 id="evento-onlanguage"><strong>Evento <em>onLanguage</em></strong></h3><p>Esta extensão será ativada sempre que um arquivo de uma determinada linguagem for aberto.</p><pre><code class="language-json">"activationEvents": [
    "onLanguage:json",
    "onLanguage:markdown",
    "onLanguage:typescript"
]
</code></pre><p>O evento onLanguage toma um <a href="https://code.visualstudio.com/docs/languages/identifiers">valor identificador de linguagem</a>. Você pode declarar tantas linguagens quantas desejar.</p><p><strong>Extensões populares com este evento de ativação</strong>: a maioria das extensões na <a href="https://marketplace.visualstudio.com/search?target=VSCode&amp;category=Programming%20Languages&amp;sortBy=Installs">categoria "Linguagens de Programação"</a> no Visual Studio Code Marketplace tem uma entrada <em>onLanguage</em> junto dos outros eventos de ativação, <a href="https://marketplace.visualstudio.com/items?itemName=octref.vetur">Vetur</a> (5,6 milhões de instalações – ativa somente para <em>Vue</em>), <a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml">YAML</a> (4,3 milhões de instalações – ativa somente para YAML), <a href="https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments">Better Comments</a> (1,1 milhão de instalações – ativa somente para linguagens suportadas).</p><h3 id="evento-workspacecontains"><strong>Evento <em>workspaceContains</em> </strong></h3><p>Esta extensão será ativada sempre que você abrir uma pasta que contenha pelo menos um arquivo que corresponda a um padrão global.</p><pre><code class="language-json">"activationEvents": [
    "workspaceContains:**/package.json"
]
</code></pre><h3 id="evento-oncommand"><strong>Evento <strong><em>onCommand</em> </strong></strong></h3><p>Esta extensão será ativada sempre que você invocar um comando.</p><pre><code class="language-json">"activationEvents": [
        "onCommand:vscode-docker.compose.down",
        "onCommand:vscode-docker.compose.restart",
        "onCommand:vscode-docker.compose.up",
        ...
]
</code></pre><h3 id="outros-eventos-de-ativa-o"><strong>Outros eventos de ativação</strong></h3><p>Você pode ler a <a href="https://code.visualstudio.com/api/references/activation-events">lista completa de eventos de ativação</a> na documentação de referência.</p><h3 id="as-extens-es-definem-um-escopo-espec-fico-de-modo-consistente"><strong>As extensões definem um escopo específico de modo consistente?</strong></h3><p>Não!</p><p>Muitas extensões utilizam o evento de ativação *.</p><p>É assim que eu classificaria a definição do escopo de algumas das extensões que usei:</p><ul><li><strong>O bom</strong>: <a href="https://marketplace.visualstudio.com/items?itemName=octref.vetur">Vetur</a>, <a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml">YAML</a>, <a href="https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments">Better Comments</a>.</li><li><strong>O mau: </strong></li></ul><p><a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Prettier</a>: seria melhor visar apenas as linguagens que ele suporta. 	</p><p><a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one">Markdown All in One</a>: está ativo quando um arquivo de marcação está aberto, ou quando o espaço de trabalho contém um README.md. Este último me parece desnecessário.</p><ul><li><strong>O feio</strong>: Todas as extensões com o <em>evento de ativação</em> * mencionado acima.</li></ul><h2 id="que-impacto-pode-ter-o-bundling-no-desempenho-de-uma-extens-o"><strong>Que impacto pode ter o <em>bundling</em> no desempenho de uma extensão?</strong></h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/burger-bundle.jpg" class="kg-image" alt="burger-bundle" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/burger-bundle.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/burger-bundle.jpg 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/03/burger-bundle.jpg 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/burger-bundle.jpg 2000w" sizes="(min-width: 720px) 720px" width="2000" height="1125" loading="lazy"><figcaption>Edição de uma imagem sem título criada por <a href="https://unsplash.com/@pablomerchanm?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Pablo Merchán Montes</a>, extraída do <a href="https://unsplash.com/s/photos/burger?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Pode causar um grande impacto!</p><p>John Papa fala sobre isso em seu artigo "<a href="https://dev.to/azure/is-your-vs-code-extension-slow-heres-how-to-speed-it-up-4d66">Is Your VS Code Extension Slow? Here's How to Speed it Up!</a>".</p><p>Ele revela os resultados de uma revisão de 2 das extensões da Microsoft:</p><ol><li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account&amp;wt.mc_id=devto-blog-jopapa">Azure Account</a>: o <em>bundling</em> reduziu o tempo de ativação em 50%. O tamanho da extensão foi reduzido de 6,2MB para 840KB através do <em>bundling </em>e excluindo mais arquivos (no arquivo <em>.vscodeignore</em>).</li><li><a href="https://marketplace.visualstudio.com/items?itemName=PeterJausovec.vscode-docker&amp;wt.mc_id=devto-blog-jopapa">Docker</a>: o bundling reduziu o tempo de ativação de 3,5 segundos para menos de 2 segundos. Além disso, uma consideração é o tempo de ativação a frio, que tende a ser mais lento do que outros tempos (tempo de ativação a quente). O tempo de ativação a frio passou de 20 segundos para 2 segundos.</li></ol><p>Você pode melhorar sua extensão favorita levantando esta questão com o autor da extensão. O <a href="https://code.visualstudio.com/api/working-with-extensions/bundling-extension">guia do usuário para o bundling de extensões</a> (documentação em inglês) explica como.</p><h2 id="como-verificar-o-desempenho"><strong>Como verificar o desempenho</strong></h2><p>Você pode executar o comando <strong>Desenvolvedor: Exibir Extensões em Execução </strong>para obter as estatísticas básicas sobre as extensões em execução. Ele classifica as extensões do maior para o menor tempo de ativação. O tempo é intitulado "Ativação inicial" se a extensão for carregada na inicialização.</p><p>Como você pode ver na captura de tela, ele também dá avisos sobre questões de desempenho.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/running-extensions.png" class="kg-image" alt="running-extensions" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/running-extensions.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/running-extensions.png 730w" sizes="(min-width: 720px) 720px" width="730" height="291" loading="lazy"></figure><p>Como mencionado anteriormente, vale notar que o tempo de ativação a frio (a primeira vez que uma extensão é executada) e o tempo de ativação a quente (segunda execução e posteriores) podem variar muito. Por esse motivo, deve-se basear o desempenho típico de uma extensão em uma segunda execução.</p><p>Você pode auditar o desempenho de início executando o comando <strong>Desenvolvedor: Desempenho de Inicialização</strong>. Ele abre um documento com estatísticas detalhadas sobre tópicos tais como: informações do sistema, marcas de desempenho, estatísticas de ativação de extensão, estatísticas de carregamento de módulos e muito mais.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/startup-performance1.png" class="kg-image" alt="startup-performance1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/startup-performance1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/startup-performance1.png 867w" sizes="(min-width: 720px) 720px" width="867" height="363" loading="lazy"></figure><p>Os resultados são específicos para o projeto atual e quaisquer arquivos abertos quando se executa o comando.</p><p>A seção <em>Estatísticas de ativação da extensão</em> dá uma visão mais detalhada do desempenho da extensão. É muito útil para ver os <em>eventos de ativação</em> sem a necessidade de verificar o código fonte de uma extensão.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/startup-performance.png" class="kg-image" alt="startup-performance" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/startup-performance.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/startup-performance.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/startup-performance.png 1253w" sizes="(min-width: 720px) 720px" width="1253" height="513" loading="lazy"></figure><p>Você pode ver que o VS Code carrega suas próprias extensões "centrais" para o Git, Emmet e algumas outras também na inicialização. Você não quer que a lista de extensões carregadas na inicialização se torne muito longa!</p><h2 id="pontua-o-para-algumas-das-extens-es-mais-populares"><strong>Pontuação para algumas das extensões mais populares</strong></h2><p>Estou me concentrando nas extensões que eu mesmo usei aqui. Não quero especular sobre extensões que eu realmente não usei.</p><h3 id="eslint"><strong><strong>ESLint</strong></strong></h3><p><a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">ESLint</a> é a ferramenta de análise estática mais popular para JavaScript e TypeScript. Ela destaca os problemas no editor com linhas vermelhas em forma de sublinhas.</p><ul><li><strong><strong>Autor</strong></strong>: Microsoft.</li><li><strong>Número de instalações</strong>: 11 milhões.</li><li><strong>Avaliação no Marketplace</strong>: 4.3/5 (156).</li><li><strong>Características principais</strong>: relatar problemas de sintaxe. Capacidade de corrigir automaticamente alguns problemas. </li><li><strong>Eventos de ativação</strong>: no início (*). Pode ser alterado para <em>onStartupFinished </em>em versões futuras. Veja esta <a href="https://github.com/microsoft/vscode-eslint/issues/1068">issue em aberto</a> para explicar por que essa escolha foi feita.</li><li><strong>Os recursos são otimizados</strong>: sim.</li><li><strong>Tamanho do arquivo</strong>: 133KB.</li><li><strong>Tempo de ativação no meu sistema</strong>: 39ms.</li><li><strong>Suíte de testes</strong>: parece ser muito básica. Apenas um pequeno teste de padrões globais. </li><li><strong>Manutenção ativa</strong>: sim.</li><li><strong>Extensões alternativas<strong>:</strong></strong> <a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.jshint">JS Hint</a>, <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin">TS Lint</a>.</li></ul><p>O ESLint é uma ótima extensão. O desempenho é excelente.</p><p>É decepcionante que ela seja carregada no início. Se isso o incomoda, você pode tentar <a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.jshint">JS Hint</a> (escrito pelo mesmo desenvolvedor) para JavaScript e <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin">TS Lint</a> para TypeScript. Ou você mesmo pode fazer o fork do projeto e mudá-lo!</p><p>Ela é mantida ativamente. Não possui um conjunto significativo de testes.</p><p><strong>Nota<strong>: 8/10</strong></strong></p><h3 id="prettier-formatador-do-c-digo"><strong><strong>Prettier - </strong>Formatador do código</strong></h3><p><a href="https://prettier.io/">Prettier</a> é um formatador de código com opinião. Atualmente, ele suporta os seguintes idiomas: JavaScript, TypeScript, Flow, JSX, JSON, CSS, SCSS, Less, HTML, Vue, Angular, GraphQL, Markdown e YAML.</p><ul><li><strong><strong>Autor</strong></strong>: Prettier.</li><li><strong>Número de instalações</strong>: 8,5 milhões.</li><li><strong>Avaliação no Marketplace<strong>:</strong></strong> 3.8/5 (204).</li><li><strong>Características principais</strong>: formatação de código.</li><li><strong>Eventos de ativação</strong>: <code>onStartupFinished</code>.</li><li><strong>Os recursos são otimizados</strong>: sim.</li><li><strong>Tamanho do arquivo</strong>: 2,1MB.</li><li><strong>Tempo de ativação em meu sistema</strong>: 286ms.</li><li><strong>Suíte de testes</strong>: sim. A cobertura parece boa.</li><li><strong>Manutenção ativa</strong>: sim.</li><li><strong>Extensões alternativas<strong>:</strong></strong> <a href="https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify">Beautify</a>.</li></ul><p>O Prettier faz um excelente trabalho na simplificação da formatação de códigos.</p><p>O desempenho é bom, mas talvez possa ser melhorado. Ele está no lado mais lento do espectro de ativação.</p><p>O escopo de ativação é muito amplo. Seria preferível visar apenas as linguagens suportadas. Encontrei um problema com a formatação de Markdown, por isso não uso atualmente para formatar Markdown. Essas são coisas que podem ser mudadas facilmente.</p><p><strong>Nota<strong>: 7</strong>,<strong>5/10.</strong></strong></p><h3 id="live-server"><strong><strong>Live Server</strong></strong></h3><p>O <a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer">Live Server</a> lança um servidor de desenvolvimento local para dar uma prévia ao vivo dos seus arquivos HTML e SVG.</p><ul><li><strong><strong>Autor</strong></strong>: Retwick Dey.</li><li><strong>Número de instalações</strong>: 7,5 milhões.</li><li><strong>Avaliação no Marketplace<strong>:</strong></strong> 4,5/5 (269).</li><li><strong>Características principais</strong>: HTML e SVG pré-visualização ao vivo.</li><li><strong>Eventos de ativação</strong>: no início (<code>*</code>).</li><li><strong>Os recursos são otimizados</strong>: não.</li><li><strong>Tamanho do arquivo</strong>: 2,5MB.</li><li><strong>Tempo de ativação em meu sistema</strong>: 2513ms.</li><li><strong>Suíte de testes</strong>: sim. Testes básicos.</li><li><strong>Manutenção ativa</strong>: não. O último commit foi há um ano. O autor da extensão está à procura de um novo mantenedor.</li><li><strong>Extensões alternativas<strong>:</strong></strong> não encontrei nenhuma!</li></ul><p>Quando funciona, é uma extensão conveniente para o uso.</p><p>O desempenho é ruim e a manutenção não é mais realizada.</p><p>Eu recomendaria que alguém se tornasse o mantenedor e que a colocasse em ordem. Caso contrário, que se encontre outra extensão para o trabalho.</p><p><strong>Nota<strong>: 5/10.</strong></strong></p><h3 id="gitlens"><strong><strong>GitLens</strong></strong></h3><p>O <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLens</a> ajuda a visualizar a autoria do código e a explorar os repositórios Git.</p><ul><li><strong><strong>Autor</strong></strong>: Eric Amodio.</li><li><strong>Número de instalações</strong>: 6,5 milhões.</li><li><strong>Avaliação no Marketplace<strong>:</strong></strong> 4,86/5 (387)</li><li><strong>Características principais</strong>: visualização da autoria do código em um olhar. Ricas vistas laterais da barra lateral dos repositórios git.</li><li><strong>Eventos de ativação</strong>: no início (<code>*</code>).</li><li><strong>Os recursos são otimizados</strong>: sim.</li><li><strong>Tamanho do arquivo</strong>: 1,5MB.</li><li><strong>Tempo de ativação em meu sistema</strong>: 35ms.</li><li><strong>Suíte de testes</strong>: não.</li><li><strong>Manutenção ativa</strong>: sim, mas a atividade recente é baixa. O último compromisso foi há 4 meses.</li><li><strong>Extensões alternativas</strong>: nenhuma.</li></ul><p>O GitLens é uma boa ideia e pode ser útil para obter perspectivas em uma base de código.</p><p>Está bem escrito e o desempenho é excelente.</p><p>Usei apenas a extensão das anotações de culpa, mas há muitas características e opções de configuração (135 configurações individuais).</p><p>Existem configurações para habilitar cada uma das características, o que é uma abordagem muito boa. Você pode ligar e desligar os codelens facilmente.</p><p>Houve uma pausa na atividade recentemente. Não sei se essa é uma situação temporária ou não. Portanto, é difícil dizer quão bem as extensões serão suportadas no futuro. O autor tem detalhes para apoiá-lo.</p><p><strong>Nota<strong>: 9/10.</strong></strong></p><h3 id="vetur"><strong><strong>Vetur</strong></strong></h3><p>Suporte à linguagem com o Vue</p><ul><li><strong><strong>Autor</strong></strong>: Pine Wu.</li><li><strong>Número de instalações</strong>: 5,6 milhões.</li><li><strong>Avaliação no Marketplace<strong>:</strong></strong> 4,5/5 (117)</li><li><strong>Características principais</strong>: destaque da sintaxe. Intellisense. Formatação de código.</li><li><strong>Eventos de ativação</strong>: <code>onLanguage: vue</code>.</li><li><strong>Os recursos são otimizado</strong>s: não.</li><li><strong>Tamanho do arquivo</strong>: 70,6 MB.</li><li><strong>Tempo de ativação em meu sistema</strong>: 252ms. No entanto, a estatística "Ativar Fim" é de 3943ms!</li><li><strong>Suíte de testes</strong>: sim.</li><li><strong>Manutenção ativa</strong>: sim.</li><li><strong>Extensões alternativas<strong>:</strong></strong> nenhuma extensão alternativa óbvia. A formatação pode ser feita com Prettier.</li></ul><p>O Vetur é a extensão para o desenvolvimento de aplicações em Vue no VS Code.</p><p>As sintaxes destacadas, o Intellisense e o hover são ótimos para o desenvolvimento em Vue.</p><p>O tamanho da extensão é ENORME.</p><p>O desempenho é um pouco errático. Leva pelo menos 4 segundos na minha máquina para terminar a ativação, o que é muito mais longo do que as <em>características integradas da linguagem JavaScript</em>. Há também um atraso notável para o autocompletar da sintaxe de JavaScript.</p><p>Os desenvolvedores estão trabalhando no momento no <em>bundling </em>da extensão. Nesse quesito, portanto, esperamos que haja uma melhoria no desempenho em breve.</p><p><strong>Nota<strong>: 7/10.</strong></strong></p><h3 id="settings-sync"><strong><strong>Settings Sync</strong></strong></h3><p>O <a href="https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync">Settings Sync</a> sincroniza as configurações usando o GitHub Gist.</p><ul><li><strong><strong>Autor</strong></strong>: Shan Khan.</li><li><strong>Número de instalações</strong>: 2 milhões.</li><li><strong>Avaliação no Marketplace<strong>:</strong></strong> 4,61/5 (638)</li><li><strong>Características principais</strong>: configurações de sincronização.</li><li><strong>Eventos de ativação</strong>: no início (<code>*</code>).</li><li><strong>Os recursos são otimizados</strong>: sim.</li><li><strong>Tamanho do arquivo</strong>: 1,2 MB.</li><li><strong>Tempo de ativação em meu sistema</strong>: 2513ms.</li><li><strong>Suíte de testes</strong>: sim.</li><li><strong>Manutenção ativa</strong>: não. O último commit foi há 1 ano.</li><li><strong>Extensões alternativas</strong>: esse é um <a href="https://code.visualstudio.com/docs/editor/settings-sync">recurso integrado no </a><a href="https://code.visualstudio.com/docs/editor/settings-sync">VS Code</a> (documentação em inglês).</li></ul><p>Essa foi uma extensão destacada. A sincronização de toda a configuração do seu editor entre as máquinas é superútil.</p><p>Desde julho de 2020, a mesma funcionalidade é uma característica integrada no VS Code para isso. A principal diferença é que essa extensão salva suas configurações para um gist, que você tem a opção de compartilhar com outros também.</p><p>O tempo de ativação é bastante lento. É justificadamente lento? É difícil dizer.</p><p>Meu palpite é que o recurso integrado fará um trabalho melhor eventualmente, pois tem o apoio da Microsoft. A extensão parece não ser mais suportada.</p><p><strong>Nota<strong>: 8/10.</strong></strong></p><h3 id="markdown-all-in-one"><strong><strong>Markdown All in One</strong></strong></h3><p><a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one">Markdown All in One</a> preenchem muitas de suas necessidades de marcação.</p><ul><li><strong><strong>Autor</strong></strong>: Yu Zhang.</li><li><strong>Número de instalações</strong>: 1,7 milhões.</li><li><strong>Avaliação no Marketplace<strong>:</strong></strong> 4,8/5 (90)</li><li><strong>Características principais</strong>: edição em estilo "toggle". Tabela de conteúdo. </li><li><strong>Eventos de ativação</strong>: &nbsp;<code>onLanguage: markdown</code>, <code>onCommand: markdown.extension.printToHtmlBatch</code>, <code>workspaceContains: README.md</code>.</li><li><strong>Os recursos são otimizados</strong>: sim.</li><li><strong>Tamanho do arquivo</strong>: 4,1 MB.</li><li><strong>Tempo de ativação em meu sistema</strong>: 195ms.</li><li><strong>Suíte de testes</strong>: sim.</li><li><strong>Manutenção ativa</strong>: sim.</li><li><strong>Extensões alternativas<strong>:</strong></strong> <a href="https://marketplace.visualstudio.com/items?itemName=robole.marky-markdown">Marky Markdown</a>.</li></ul><p>É uma extensão ótima e o desempenho é excelente.</p><p>Tem muitas características para o meu gosto. Para muitas pessoas, é atraente ter tudo o que possam querer em uma única extensão.</p><p>O evento de ativação <code><em>workspaceContains</em>: README.md</code> parece uma inclusão desnecessária para mim. A maioria dos meus projetos tem um README, mas eu raramente os edito. Portanto, para mim, é como ter a extensão sempre ativa.</p><p>A lógica para a tabela de conteúdos é um pouco comum. Ela teve alguns problemas com falsos positivos no passado. Não sei se isso foi completamente eliminado.</p><p>O tamanho do arquivo da extensão pode ser reduzido excluindo as capturas de tela README do pacote de extensão.</p><p><strong>Nota<strong>: 8/10.</strong></strong></p><h2 id="dicas-de-desempenho-geral"><strong>Dicas de desempenho geral</strong></h2><h3 id="use-um-so-de-64-bits"><strong><strong>Use </strong>um SO<strong> </strong>de <strong>64</strong> <strong>bit</strong>s</strong></h3><p>Se você atualizar para uma versão de 64 bits de um sistema operacional, pode expandir a quantidade de memória virtual (VM) disponível para o VS Code de 2 GB para 4 GB.</p><p>Isto permite que o VS Code possa lidar com cargas de trabalho significativamente maiores quando a VM é necessária.</p><h3 id="desative-a-restaura-o-do-estado-do-projeto-no-in-cio-da-opera-o"><strong>Desative a restauração do estado do projeto no início da operação</strong></h3><p>O VS Code restaura automaticamente o estado do projeto a partir da sessão anterior. Isso pode prolongar o tempo necessário para carregar um projeto.</p><p>Você pode desativar algumas das configurações de restauração para acelerar o tempo de carregamento:</p><ul><li><code>Workbench › Editor: Restore View State</code>: ativado por padrão.</li><li><code>Files: Restore Undo Stack</code>: ativado por padrão.</li><li><code>Workbench: Startup Editor</code>: controla qual editor é mostrado na inicialização. A página padrão é a de boas-vindas. Você pode defini-la para "nenhuma" para prevenir que qualquer editor apareça na inicialização.</li></ul><h3 id="desative-recursos-caros-que-afetam-o-desempenho-de-edi-o"><strong>Desative recursos caros que afetam o desempenho de edição</strong></h3><ul><li><strong><strong>Minimap</strong></strong>: <code>Editor › Minimap: Enabled</code>, ativado por padrão.</li><li><strong><strong>Word wrap</strong></strong>: <code>Editor: Word Wrap</code>, desabilitado por padrão.</li><li><strong><strong>CodeLens</strong></strong>: <code>Editor: CodeLens</code>, ativado por padrão.</li><li><strong><strong>Format on Save</strong></strong>: <code>Editor: Format On Save</code>, desabilitado por padrão.</li><li><strong><strong>Format on Paste</strong></strong>: <code>Editor: Format On Paste</code>, desabilitado por padrão.</li></ul><h3 id="desative-extens-es-para-um-espa-o-de-trabalho"><strong>Desative extensões para um espaço de trabalho</strong></h3><p>Você pode desativar uma extensão para um espaço de trabalho (projeto).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/disable-extension-workspace.png" class="kg-image" alt="disable-extension-workspace" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/disable-extension-workspace.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/disable-extension-workspace.png 761w" sizes="(min-width: 720px) 720px" width="761" height="213" loading="lazy"></figure><p>O mais provável é que você queira fazer isso para extensões que funcionem sempre. Para um projeto Java, você não vai precisar de ESLint!</p><p>Você também pode adotar a abordagem oposta. Você pode desativar uma extensão globalmente e somente habilitá-la para um número seleto de projetos.</p><h3 id="crie-conjuntos-de-extens-es"><strong>Crie conjuntos de extensões</strong></h3><p>Você pode especificar um diretório alternativo para extensões a partir da linha de comando, como abaixo.</p><pre><code class="language-bash">code --extensions-dir &lt;dir&gt;
</code></pre><p>Portanto, se você quiser usar diferentes conjuntos de extensões, você pode. Você pode adicionar um atalho de área de trabalho para isso, ou um <em>alias</em> para executar isto regularmente a partir da linha de comando.</p><p>Uma coisa a se ter em mente é a sincronização. Se você sincronizar suas extensões entre máquinas, você pode querer excluir extensões da sincronização. Caso contrário, você pode estragar sua pasta por engano ao trocar.</p><p>O ideal é que você não precise fazer isso.</p><h3 id="desative-todas-as-extens-es-para-uma-sess-o"><strong>Desative todas as extensões para uma sessão</strong></h3><p>Você pode iniciar o VS Code com todas as extensões de usuário desabilitadas a partir da linha de comando. Modo Zen no seu máximo!</p><pre><code class="language-bash">code --disable-extensions
</code></pre><h2 id="solu-o-de-problemas-de-desempenho"><strong>Solução de problemas de desempenho</strong></h2><h3 id="lentid-o-ou-uma-tela-em-branco"><strong>Lentidão ou uma tela em branco</strong></h3><p>O VS Code tem problemas com a aceleração de hardware da GPU (unidade de processamento gráfico) em alguns sistemas. Você pode ver se esse é o caso, desativando a aceleração da GPU.</p><pre><code class="language-bash">code --disable-gpu
</code></pre><p>Para definir isso permanentemente, faça o seguinte:</p><ul><li>Abra a Paleta de Comando (Ctrl+Shift+P).</li><li>Execute o comando <strong><strong>Prefer</strong>ências<strong>: Configur</strong>ar<strong> </strong>Argumentos de Runtime</strong>. Esse comando abrirá um arquivo <code>argv.json</code> para configurar argumentos de tempo de execução. Você já pode ver alguns argumentos padrão lá.</li><li>Adicione <code>"disable-hardware-acceleration": true</code>.</li><li>Reinicie o VS Code.</li></ul><h3 id="instala-o-parece-estar-corrompida-com-a-mensagem-unsupported-"><strong>Instalação parece estar corrompida com a mensagem [Unsupported].</strong></h3><p>O VS Code faz uma verificação de antecedentes quando inicia para verificar se você alterou algum de seus arquivos fonte. Se esse for o caso, você verá o texto <strong>[Unsupported]</strong> na barra de título.</p><p>Uma das causas desse problema pode ser o software antivírus. O VS Code pode ter sido colocado em quarentena por engano ou ter tido arquivos removidos pelo software antivírus (ver questão <a href="https://github.com/microsoft/vscode/issues/94858">#94858</a>). Verifique as suas configurações do software antivírus para prevenir isso.</p><p>Para resolver essa situação, você pode <a href="https://code.visualstudio.com/download">reinstalar o </a><a href="https://code.visualstudio.com/download">VS Code</a>. Isso substituirá os arquivos modificados e silenciará o aviso.</p><h2 id="palavras-finais"><strong>Palavras finais</strong></h2><p>Você não deve precisar comprometer o desempenho para obter as características de que precisa.</p><p>A abordagem mais pragmática é incrementar as extensões de que você precisa. Faça um pouco de pesquisa a cada vez e teste a extensão. Antes que você perceba, terá um portfólio incrível de extensões.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cursos de aprendizagem de máquina na internet, classificados por suas análises ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: David Venturi Há um ano e meio, desisti de um dos melhores programas de Ciência da Computação do Canadá. Comecei a criar meu próprio programa de mestrado em ciência de dados [https://medium.com/@davidventuri/i-dropped-out-of-school-to-create-my-own-data-science-master-s-here-s-my-curriculum-1b400dcee412#.5fwwphdqd]  utilizando recursos on-line. Percebi que podia aprender tudo o que precisava através da edX, do ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/cursos-de-aprendizagem-de-maquina-na-internet-classificados-por-suas-analises/</link>
                <guid isPermaLink="false">6399a851bec90f05d689363c</guid>
                
                    <category>
                        <![CDATA[ Aprendizagem de máquina ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Wed, 01 Mar 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_vBLkfW8S-ZqHb8TmNEW1XA.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/every-single-machine-learning-course-on-the-internet-ranked-by-your-reviews-3c4a7b8026c0/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Every single Machine Learning course on the internet, ranked by your reviews</a>
      </p><p>Escrito por: David Venturi</p><p>Há um ano e meio, desisti de um dos melhores programas de Ciência da Computação do Canadá. Comecei a criar meu próprio <a href="https://medium.com/@davidventuri/i-dropped-out-of-school-to-create-my-own-data-science-master-s-here-s-my-curriculum-1b400dcee412#.5fwwphdqd">programa de mestrado em ciência de dados</a> utilizando recursos on-line. Percebi que podia aprender tudo o que precisava através da edX, do Coursera e da Udacity. Eu podia, inclusive, aprender mais rápido, de modo mais eficiente e por uma pequena parte do valor.</p><p>Estou quase terminando agora. Fiz muitos cursos relacionados à ciência de dados e conferi partes de muitos outros. Conheço as opções que estão por aí e quais habilidades são necessárias para os alunos se prepararem para o papel de analista de dados ou de cientista de dados. Assim, comecei a criar um guia de revisão que recomenda os melhores cursos para cada disciplina dentro da ciência de dados.</p><p>No primeiro guia desta série, recomendei algumas <a href="https://freecodecamp.org/news/if-you-want-to-learn-data-science-start-with-one-of-these-programming-classes-fb694ffe780c#.42hhzxopw">aulas de programação</a> (texto em inglês) para o cientista de dados iniciante. Depois, foram as <a href="https://freecodecamp.org/news/if-you-want-to-learn-data-science-take-a-few-of-these-statistics-classes-9bbabab098b9#.p7pac546r">aulas de estatística e de probabilidade</a> (texto em inglês). Em seguida, <a href="https://www.freecodecamp.org/portuguese/news/classifiquei-cada-curso-de-introducao-a-ciencia-de-dados-na-internet-com-base-em-milhares-de-avaliacoes/">introdução à ciência de dados</a>. Por fim, cursos de <a href="https://freecodecamp.org/news/an-overview-of-every-data-visualization-course-on-the-internet-9ccf24ea9c9b">visualização de dados</a> (texto em inglês).</p><h2 id="agora-vamos-aprendizagem-da-m-quina-"><strong>Agora, vamos à aprendizagem da máquina.</strong></h2><p>Para este guia, passei várias horas tentando identificar cada curso de aprendizagem de máquina on-line oferecido a partir de maio de 2017, extraindo informações-chave de seus programas e análises de estudantes e compilando suas classificações. <strong>Meu objetivo final era identificar os três melhores cursos disponíveis e apresentá-los a você abaixo.</strong></p><p>Para esta tarefa, recorri a ninguém menos do que a comunidade de código aberto da Class Central e ao seu banco de dados de milhares de classificações e análises de cursos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_u1dxHyShejSN3cgXGFQIAA.png" class="kg-image" alt="1_u1dxHyShejSN3cgXGFQIAA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_u1dxHyShejSN3cgXGFQIAA.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_u1dxHyShejSN3cgXGFQIAA.png 800w" sizes="(min-width: 720px) 720px" width="800" height="482" loading="lazy"><figcaption><a href="https://www.class-central.com/">Página inicial</a> do Class Central</figcaption></figure><p>Desde 2011, o fundador da <a href="https://www.class-central.com/">Class Central</a>, <a href="https://www.freecodecamp.org/news/every-single-machine-learning-course-on-the-internet-ranked-by-your-reviews-3c4a7b8026c0/undefined">Dhawal Shah</a>, vem se mantendo atento aos cursos on-line, mais do que qualquer outra pessoa no mundo. Dhawal me ajudou pessoalmente a montar esta lista de recursos.</p><h3 id="como-escolhemos-os-cursos-que-avaliamos">Como escolhemos os cursos que avaliamos</h3><p>Os cursos precisavam se enquadrar em três critérios:</p><ol><li><strong>Deveriam ter uma quantidade significativa de conteúdo de aprendizagem de máquina</strong>: o ideal é que a aprendizagem de máquina seja o tópico principal. Observe que os cursos de aprendizagem profunda (do inglês, <em>deep learning</em>) são excluídos. Falaremos mais sobre isso depois.</li><li><strong>Deveriam ser sob demanda ou oferecidos em intervalos mensais curtos.</strong></li><li><strong>Deveriam ser cursos on-line interativos – sem livros ou tutoriais somente de leitura</strong>: embora estes sejam modos viáveis de aprender, o guia se concentra nos cursos. Os cursos que são estritamente baseados em vídeo (isto é, sem questionários, tarefas etc.) também foram excluídos.</li></ol><p>Acreditamos ter percorrido todos os cursos notáveis que se encaixam nos critérios acima. Como, aparentemente, existem centenas de cursos na <a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14494&amp;RD_PARM1=https%253A%252F%252Fwww.udemy.com%252F">Udemy</a>, optamos por considerar apenas os mais analisados e bem cotados pelos alunos.</p><p>Sempre há, porém, a chance de que tenhamos perdido algo.</p><h3 id="como-avaliamos-os-cursos"><strong>Como avaliamos os cursos</strong></h3><p>Compilamos as classificações médias e o número de análises da Class Central e de outros locais de revisão para calcular uma classificação média ponderada para cada curso. Lemos análises por texto e utilizamos este feedback para complementar as classificações numéricas.</p><p>Fizemos decisões subjetivas em termos do programa de cada curso com base em três fatores:</p><ol><li><strong>Explicação do fluxo de trabalho de aprendizagem da máquina</strong>: o curso descreve os passos necessários para executar um projeto de sucesso em aprendizagem de máquina? Veja a próxima seção para saber o que implica um fluxo de trabalho típico.</li><li><strong>Tratamento das técnicas e dos algoritmos de aprendizagem de máquina</strong>: uma variedade de técnicas (por exemplo, regressão, classificação, agrupamento, etc.) e algoritmos (por exemplo, dentro da classificação: Naive Bayes, árvores de decisão, máquinas vetoriais de suporte etc.) são tratados ou apenas alguns poucos são selecionados? É dada preferência a cursos que cubram mais, sem poupar dos detalhes.</li><li><strong>Utilização de ferramentas comuns em ciência de dados e aprendizagem de máquina</strong>: o curso é ministrado usando linguagens de programação populares como Python, R e/ou Scala? As bibliotecas populares dentro dessas linguagens são examinadas? Embora não sejam necessárias, elas são úteis e, portanto, é dada uma ligeira preferência aos cursos que tratam dessas bibliotecas.</li></ol><h3 id="o-que-aprendizagem-de-m-quina-o-que-um-fluxo-de-trabalho"><strong>O que é aprendizagem de máquina? O que é um fluxo de trabalho?</strong></h3><p>Uma definição popular tem origem em uma declaração de <a href="https://en.wikipedia.org/wiki/Arthur_Samuel">Arthur Samuel</a>, em 1959: aprendizagem de máquina é um subcampo da ciência da computação que "<em>dá aos computadores a capacidade de aprender sem serem explicitamente programados"</em>. Na prática, isto significa desenvolver programas de computador que podem fazer previsões com base em dados. Assim como os humanos podem aprender com a experiência, os computadores também podem fazê-los, sendo que, neste caso dados equivalem à experiência.</p><p>Um fluxo de trabalho de aprendizagem de máquina é o processo necessário para a realização de um projeto de aprendizagem de máquina. Embora os projetos individuais possam diferir, a maioria dos fluxos de trabalho compartilha de várias tarefas comuns: avaliação de problemas, exploração dos dados, pré-processamento de dados, treinamento/teste/desenvolvimento de modelos etc. Abaixo, você encontrará uma visualização útil destas etapas principais:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_KzmIUYPmxgEHhXX7SlbP4w.jpeg" class="kg-image" alt="1_KzmIUYPmxgEHhXX7SlbP4w" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_KzmIUYPmxgEHhXX7SlbP4w.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_KzmIUYPmxgEHhXX7SlbP4w.jpeg 800w" sizes="(min-width: 720px) 720px" width="800" height="368" loading="lazy"><figcaption>As etapas principais do fluxo de trabalho típico de aprendizagem de máquina, diagrama extraído da <a href="https://upxacademy.com/introduction-machine-learning/" rel="noopener">UpX Academy</a></figcaption></figure><p>O curso ideal introduz todo o processo e fornece exemplos interativos, tarefas e/ou questionários onde os alunos podem realizar cada tarefa por conta própria.</p><h3 id="estes-cursos-cobrem-a-aprendizagem-profunda"><strong>Estes cursos cobrem a aprendizagem profunda?</strong></h3><p>Em primeiro lugar, vamos definir a aprendizagem profunda, ou, em inglês, <em>deep learning</em>. Aqui está uma descrição sucinta:</p><blockquote><em>"A aprendizagem profunda é um subcampo de aprendizagem de máquina preocupado com os algoritmos inspirados na estrutura e função do cérebro, chamados de redes neurais artificiais".</em><br><br>—<em>Jason Brownlee, do <a href="http://machinelearningmastery.com/what-is-deep-learning/">Domínio da Aprendizagem de Máquina</a></em></blockquote><p>Como seria de se esperar, partes de alguns dos cursos de aprendizagem de máquina contêm conteúdo sobre aprendizagem profunda. No entanto, optei por não incluir cursos que sejam somente de aprendizagem profunda. Se você estiver interessado na aprendizagem profunda especificamente, temos este <a href="https://freecodecamp.org/news/dive-into-deep-learning-with-these-23-online-courses-bf247d289cc0">este artigo</a> (texto em inglês) para você:</p><p>Minhas três principais recomendações nessa lista seriam:</p><ul><li><a href="https://www.class-central.com/mooc/6679/kadenze-creative-applications-of-deep-learning-with-tensorflow" rel="noopener"><strong><strong>Creative Applications of Deep Learning with TensorFlow</strong></strong></a>,<em> da Kadenze</em></li><li><a href="https://www.class-central.com/mooc/398/coursera-neural-networks-for-machine-learning" rel="noopener"><strong><strong>Neural Networks for Machine Learning</strong></strong></a>, <em>da Universidade de Toronto (ensinado por Geoffrey Hinton), na Coursera</em></li><li><a href="http://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;offerid=507388.9689&amp;type=3&amp;subid=0&amp;u1=medium-career-guide-machine-learning" rel="noopener"><strong><strong>Deep Learning A-Z™: Hands-On Artificial Neural Networks</strong></strong></a>, de <em>Kirill Eremenko, Hadelin de Ponteves e a equipe da SuperDataScience, na Udemy</em></li></ul><h3 id="pr-requisitos-recomendados"><strong>Pré-requisitos recomendados</strong></h3><p>Vários cursos listados abaixo pedem aos estudantes que tenham experiência prévia em programação, cálculo, álgebra linear e estatística. Estes pré-requisitos são compreensíveis, dado que a aprendizagem da máquina é uma disciplina avançada.</p><p>Alguns desses assuntos não são familiares? Boas notícias! Parte desta experiência pode ser adquirida através de nossas recomendações nos dois primeiros artigos (o de <a href="https://freecodecamp.org/news/if-you-want-to-learn-data-science-start-with-one-of-these-programming-classes-fb694ffe780c#.ld31z08y5">programação</a> e o de <a href="https://freecodecamp.org/news/if-you-want-to-learn-data-science-take-a-few-of-these-statistics-classes-9bbabab098b9">estatísticas</a> – ambos os textos em inglês) deste Guia de Carreira em Ciência de Dados. Vários cursos de alto nível abaixo também fornecem revisões leves de cálculo e de álgebra linear e destacam os aspectos mais relevantes para a aprendizagem de máquina para os menos familiarizados.</p><h3 id="nossa-escolha-como-o-melhor-curso-de-aprendizagem-de-m-quina-"><strong>Nossa escolha como o melhor curso de aprendizagem de máquina é...</strong></h3><ul><li><a href="https://www.class-central.com/mooc/835/coursera-machine-learning">Machine Learning</a> (da Universidade de Stanford, na Coursera)</li></ul><p>Este curso da Universidade de Stanford na Coursera é, claramente, o vencedor atual em termos de classificação, análises e adequação do programa de estudos. Ensinado pelo famoso Andrew Ng, fundador do Google Brain e ex-cientista chefe da <a href="https://en.wikipedia.org/wiki/Baidu">Baidu</a>, essa foi a aula que acabou gerando a Coursera. Tem uma classificação média ponderada de 4,7 estrelas sobre 422 avaliações.</p><p>Lançado em 2011, ele cobre todos os aspectos do fluxo de trabalho de aprendizagem da máquina. Embora tenha um escopo menor do que a classe original de Stanford na qual se baseia, ainda consegue cobrir um grande número de técnicas e algoritmos. O tempo estimado de conclusão é de onze semanas, com duas semanas dedicadas às redes neurais e a aprendizagem profunda. Opções gratuitas e pagas estão disponíveis.</p><p>Andrew Ng é um instrutor dinâmico, mas gentil, com uma experiência palpável. Ele inspira confiança, especialmente ao compartilhar dicas práticas de implementação e avisos sobre armadilhas comuns. É fornecido uma revisão de álgebra linear e o autor destaca os aspectos de cálculo mais relevantes para a aprendizagem da máquina.</p><p>A avaliação é automática e feita através de questionários de múltipla escolha que seguem cada lição e tarefas de programação. As (oito) tarefas podem ser concluídas no MATLAB ou no Octave, que é uma versão de código aberto do MATLAB. Andrew Ng explica sua escolha de linguagem:</p><blockquote><em>No passado, tentei ensinar a aprendizagem de máquina usando uma grande variedade de linguagens de programação, incluindo C++, Java, Python, NumPy e também o Octave... o que eu vi depois de ter ensinado a aprendizagem de máquina por quase uma década é que você aprende muito mais rápido se usar Octave como seu ambiente de programação.</em></blockquote><p>Embora o Python e o R sejam, provavelmente, escolhas mais utilizadas com o <a href="http://blog.codeeval.com/codeevalblog/2016/2/2/most-popular-coding-languages-of-2016">aumento da popularidade dessas linguagens</a> (texto em inglês), os comentários das análises observam que isso não deve impedi-lo de acompanhar o curso.</p><p>Alguns comentários de destaque observaram o seguinte:</p><blockquote><em>De renome de longa data no mundo da MOOC, o curso de aprendizagem de máquina de Stanford é realmente a introdução definitiva ao tópico. O curso cobre amplamente todas as principais áreas da aprendizagem de máquina... o Prof. Ng precede cada segmento com uma discussão motivadora e exemplos. </em></blockquote><blockquote><em>Andrew Ng é um professor talentoso e capaz de explicar assuntos complicados de um modo muito intuitivo e claro, incluindo a matemática por trás de todos os conceitos. &nbsp;</em>Altamente recomendado.</blockquote><p>O único problema que vejo com este curso é que ele estabelece expectativas muito altas para outros cursos em termos de comparação.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_viCB-ayFFQi-4Fs_NYLVVQ.png" class="kg-image" alt="1_viCB-ayFFQi-4Fs_NYLVVQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_viCB-ayFFQi-4Fs_NYLVVQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_viCB-ayFFQi-4Fs_NYLVVQ.png 800w" sizes="(min-width: 720px) 720px" width="800" height="168" loading="lazy"></figure><h3 id="uma-nova-introdu-o-ao-tema-com-um-professor-brilhante"><strong>Uma nova introdução ao tema com um professor brilhante</strong></h3><ul><li><a href="https://www.class-central.com/mooc/7231/edx-machine-learning" rel="noopener">Machine Learning</a> (criado pela Universidade de Columbia, na edX)</li></ul><p>Este é um curso relativamente novo que faz parte dos MicroMasters (em português, algo como "micromestrados") de Inteligência Artificial da edX. Embora seja mais novo e não tenha um grande número de análises, as que tem são excepcionalmente fortes. O professor John Paisley é mencionado como sendo brilhante, claro e inteligente. O curso tem uma classificação média ponderada de 4,8 estrelas em 10 análises.</p><p>O curso também cobre todos os aspectos do fluxo de aprendizagem da máquina e mais algoritmos do que a oferta da Stanford acima. O curso da Universidade de Columbia é uma introdução mais avançada, com os comentários observando que os alunos devem se sentir confortáveis com os pré-requisitos recomendados (cálculo, álgebra linear, estatística, probabilidade e programação).</p><p>Questionários (11), tarefas de programação (4) e um exame final são os modos de avaliação. Os alunos podem usar Python, Octave ou MATLAB para completar as tarefas. O tempo total estimado do curso é de oito a dez horas por semana durante doze semanas. Ele é gratuito com um certificado verificado disponível para compra.</p><p>Abaixo estão algumas das <a href="https://www.coursetalk.com/providers/edx/courses/machine-learning-5">análises</a> acima mencionadas:</p><blockquote><em>Ao longo de todos os meus anos [como aluno] encontrei professores que não são brilhantes, professores que são brilhantes mas não sabem como explicar as coisas claramente e professores que são brilhantes e sabem como explicar as coisas claramente. O Dr. Paisley pertence ao terceiro grupo.</em></blockquote><blockquote>Este é um ótimo curso... a linguagem do instrutor é precisa e isso é, na minha opinião, um dos pontos mais fortes do curso. As palestras são de alta qualidade e os slides também são ótimos.<br><br>O Dr. Paisley e seu supervisor são ... alunos de Michael Jordan, o pai da aprendizagem de máquina. [Dr. Paisley] é o melhor professor de ML (Machine Learning - Aprendizagem de Máquina) de Columbia por causa de sua capacidade de explicar as coisas claramente. Em torno de 240 alunos selecionaram seu curso neste semestre, o maior número entre todos os professores [que ensinam] aprendizagem de máquina em Columbia.</blockquote><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_q4Qa-kxC6MXFwct_9635ug.png" class="kg-image" alt="1_q4Qa-kxC6MXFwct_9635ug" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_q4Qa-kxC6MXFwct_9635ug.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_q4Qa-kxC6MXFwct_9635ug.png 800w" sizes="(min-width: 720px) 720px" width="800" height="123" loading="lazy"></figure><h3 id="uma-introdu-o-pr-tica-em-python-e-em-r-de-especialistas-do-setor"><strong>Uma introdução prática em Python e em R de especialistas do setor</strong></h3><ul><li><a href="http://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;offerid=507388.9688&amp;type=3&amp;subid=0&amp;u1=cc-career-guide-machine-learning&amp;u1=medium-career-guide-machine-learning" rel="noopener">Machine Learning A-Z™: Hands-On Python &amp; R In Data Science</a> <a href="http://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;offerid=507388.9688&amp;type=3&amp;subid=0&amp;u1=cc-career-guide-machine-learning&amp;u1=medium-career-guide-machine-learning">(Kirill Eremenko, Hadelin de Ponteves e a equipe da SuperDataScience</a>, na Udemy)</li></ul><p><a href="http://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;offerid=507388.9688&amp;type=3&amp;subid=0&amp;u1=cc-career-guide-machine-learning&amp;u1=medium-career-guide-machine-learning" rel="noopener">Machine Learning A-Z™</a>, da Udemy, é uma oferta impressionantemente detalhada, que fornece instrução tanto em Python quanto em R, o que é raro e não pode ser dito de nenhum dos outros cursos superiores. Tem uma classificação média ponderada de 4,5 estrelas, com 8.119 análises, o que o torna o curso mais analisado dentre os que revisamos.</p><p>Ele cobre todo o fluxo de aprendizagem da máquina e um número quase absurdo de algoritmos nas 40,5 horas de vídeo sob demanda. O curso tem uma abordagem mais aplicada e é mais leve em termos de matemática do que os dois cursos acima. Cada seção começa com um vídeo "intuitivo" de Eremenko, que resume a teoria subjacente do conceito que está sendo ensinado. Hadelin de Ponteves, então, mostra a implementação com vídeos separados, tanto para Python quanto para R.</p><p>Como "bônus", o curso inclui modelos de código em Python e em R para que os alunos possam baixar e utilizar em seus próprios projetos. Há questionários e desafios de lição de casa, embora estes não sejam os pontos fortes do curso.</p><p>Eremenko e a equipe da SuperDataScience são reverenciados por sua capacidade de "tornar o complexo simples". Além disso, os pré-requisitos listados são "apenas matemática do ensino médio". Portanto, este curso pode ser uma opção melhor para aqueles desencorajados com as ofertas de Stanford e de Columbia.</p><p>Algumas das análises mais destacadas <a href="https://www.udemy.com/machinelearning/#reviews">observaram</a> o seguinte:</p><blockquote><em>O curso é produzido profissionalmente, a qualidade do som é excelente e as explicações são claras e concisas... é um valor incrível para seu investimento financeiro e de tempo.</em></blockquote><blockquote>Foi espetacular poder acompanhar o curso em duas linguagens de programação diferentes simultaneamente.<br>Kirill (Eremenko) é um dos melhores instrutores da Udemy (se não da internet) e eu recomendo que se faça qualquer aula que ele ensine. ... Este curso tem muito conteúdo, de verdade!</blockquote><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_gl_KL2hhIkodQpznSzu8ZA.png" class="kg-image" alt="1_gl_KL2hhIkodQpznSzu8ZA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_gl_KL2hhIkodQpznSzu8ZA.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_gl_KL2hhIkodQpznSzu8ZA.png 800w" sizes="(min-width: 720px) 720px" width="800" height="265" loading="lazy"></figure><h3 id="os-concorrentes"><strong>Os concorrentes</strong></h3><p>Nossa escolha número 1 teve uma classificação média ponderada de 4,7 de 5 estrelas em 422 análises. Vejamos as outras alternativas, ordenadas por classificação decrescente. Lembramos que cursos que sejam apenas de aprendizagem profunda não estão incluídos neste guia – você pode encontrá-los <a href="https://freecodecamp.org/news/dive-into-deep-learning-with-these-23-online-courses-bf247d289cc0">aqui</a> (texto em inglês).</p><p><a href="https://www.class-central.com/mooc/1623/edx-the-analytics-edge">The Analytics Edge</a> (Instituto de Tecnologia de Massachusetts/edX): mais focado na análise em geral, embora abranja vários tópicos de aprendizagem de máquina. Utiliza R. Narrativa forte, que aproveita exemplos familiares do mundo real. Desafiador. Dez a quinze horas por semana ao longo de doze semanas. Gratuito, com um certificado verificado disponível para compra. Tem uma classificação média ponderada de 4,9 estrelas em 214 análises.</p><p><a href="http://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;offerid=507388.9690&amp;type=3&amp;subid=0&amp;u1=medium-career-guide-machine-learning" rel="noopener">Python for Data Science and Machine Learning Bootcamp</a> (Jose Portilla/Udemy): tem grande parte do conteúdo de aprendizagem de máquina, mas cobre todo o processo de ciência de dados. Mais uma introdução muito detalhada ao Python. Curso surpreendente, embora não ideal para o escopo deste guia. 21,5 horas de vídeo sob demanda. O custo varia, dependendo dos descontos da Udemy, que são frequentes. Tem uma classificação média ponderada de 4,6 estrelas em 3316 análises.</p><p><a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fdata-science-and-machine-learning-bootcamp-with-r%2F" rel="noopener">Data Science and Machine Learning Bootcamp with R</a> (Jose Portilla/Udemy): os comentários para o curso de Portilla acima também se aplicam aqui, exceto pelo fato de que o curso é em linguagem R. 17,5 horas de vídeo sob demanda. O custo varia, dependendo dos descontos da Udemy, que são frequentes. Tem uma classificação média ponderada de 4,6 estrelas em 1317 análises.</p><p><a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fuser%2Flazy-programmer%2F" rel="noopener">Machine Learning Series</a> (Lazy Programmer Inc./Udemy): ensinado por um cientista de dados/engenheiro de software de big data/engenheiro de software <em>full-stack</em> com um currículo impressionante, Lazy Programmer tem atualmente uma série de 16 cursos focados na aprendizagem de máquina na Udemy. No total, os cursos têm mais de 5 mil classificações e quase todas elas têm 4,6 estrelas. A descrição de cada curso individual fornece um ordenamento útil do curso. Utiliza Python. O custo varia, dependendo dos descontos da Udemy, que são frequentes.</p><p><a href="https://www.class-central.com/mooc/1020/udacity-machine-learning" rel="noopener">Machine Learning</a> (Georgia Tech/Udacity): uma compilação do que eram três cursos separados: aprendizagem supervisionada, sem supervisão e aprendizagem de reforço. Parte do Nanodegree de Engenheiro de Aprendizagem de Máquina, da Udacity, e do mestrado on-line (OMS), da Georgia Tech. Os vídeos são curtos, como é o estilo da Udacity. Os professores são simpáticos. O tempo estimado é de quatro meses. Gratuito. Tem uma classificação média ponderada de 4,56 estrelas em 9 análises.</p><p><a href="https://www.class-central.com/mooc/4151/edx-implementing-predictive-analytics-with-spark-in-azure-hdinsight" rel="noopener">Implementing Predictive Analytics with Spark in Azure HDInsight</a><a href="https://www.class-central.com/mooc/4151/edx-implementing-predictive-analytics-with-spark-in-azure-hdinsight"> </a>(Microsoft/edX): introduz os conceitos centrais de aprendizagem de máquina e uma variedade de algoritmos. Tira proveito de várias grandes ferramentas de dados amigáveis, incluindo Apache Spark, Scala e Hadoop. Utiliza tanto Python, quanto R. Quatro horas por semana durante seis semanas. Gratuito com um certificado verificado disponível para compra. Tem uma classificação média ponderada de 4,5 estrelas em 6 análises.</p><p><a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fdata-science-and-machine-learning-with-python-hands-on%2F" rel="noopener">Data Science and Machine Learning with Python — Hands On!</a> (Frank Kane/Udemy): utiliza Python. Kane tem nove anos de experiência na Amazon e na IMDb. Nove horas de vídeo sob demanda. O custo varia, dependendo dos descontos da Udemy, que são frequentes. Tem uma classificação média ponderada de 4,5 estrelas em 4139 análises.</p><p><a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fscala-and-spark-for-big-data-and-machine-learning%2F" rel="noopener">Scala and Spark for Big Data and Machine Learning</a> (Jose Portilla/Udemy): o foco é em "Big Data", especificamente na implementação em Scala e Spark. Dez horas de vídeo sob demanda. O custo varia, dependendo dos descontos da Udemy, que são frequentes. Tem uma classificação média ponderada de 4,5 estrelas em 607 análises.</p><p><a href="https://www.class-central.com/certificate/machine-learning-engineer-nanodegree--nd009" rel="noopener">Machine Learning Engineer Nanodegree</a> (Udacity): o principal programa de Machine Learning do Udacity, que apresenta o melhor sistema de análise de projetos e suporte de carreira. O programa é uma compilação de vários cursos individuais da Udacity, que são gratuitos. Co-criado pela Kaggle. Cronograma estimado de seis meses. Atualmente, custa US$ 199 por mês, com um reembolso de 50% da mensalidade disponível para aqueles que se formarem dentro de 12 meses. Tem uma classificação média ponderada de 4,5 estrelas em 2 análises.</p><p><a href="https://www.class-central.com/mooc/1240/edx-learning-from-data-introductory-machine-learning" rel="noopener">Learning From Data (Introductory Machine Learning)</a> (California Institute of Technology/edX): a inscrição está, atualmente, fechada na edX, mas também está disponível através da plataforma independente da CalTech (veja abaixo). Tem uma classificação média ponderada de 4,49 estrelas em 42 análises.</p><p><a href="https://www.class-central.com/mooc/366/learning-from-data-introductory-machine-learning-course" rel="noopener">Learning From Data (Introductory Machine Learning)</a> (Yaser Abu-Mostafa/California Institute of Technology): "um verdadeiro curso da Caltech, não uma versão diluída". As revisões observam que é excelente para entender a teoria da aprendizagem de máquina. O professor, Yaser Abu-Mostafa, é popular entre os estudantes e também escreveu o livro didático no qual este curso se baseia. Os vídeos são as aulas gravadas (com slides das aulas) e se encontram no YouTube. As tarefas de casa são arquivos em formato .pdf. A experiência do curso para estudantes on-line não é tão adequada quanto as três principais recomendações. Tem uma média ponderada de 4,43 estrelas em 7 análises.</p><p><a href="https://www.class-central.com/mooc/2406/stanford-openedx-mining-massive-datasets">Mining Massive Datasets</a> (Universidade de Stanford): aprendizagem de máquina com foco em "Big Data". Introduz modernos sistemas de arquivos distribuídos e MapReduce. Dez horas por semana durante sete semanas. Gratuito. Tem uma classificação média ponderada de 4,4 estrelas em 30 análises.</p><p><a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Faws-machine-learning-a-complete-guide-with-python%2F" rel="noopener">AWS Machine Learning: A Complete Guide With Python</a> (Chandra Lingam/Udemy): um foco único na aprendizagem de máquina baseado em nuvem e, especificamente, nos Amazon Web Services. Utiliza Python. Nove horas de vídeo sob demanda. O custo varia dependendo dos descontos da Udemy, que são frequentes. Tem uma classificação média ponderada de 4,4 estrelas em 62 análises.</p><p><a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fintroduction-to-machine-learning-in-python%2F" rel="noopener">Introduction to Machine Learning &amp; Face Detection in Python</a> (Holczer Balazs/Udemy): utiliza Python. Oito horas de vídeo sob demanda. O custo varia, dependendo dos descontos da Udemy, que são frequentes. Tem uma classificação média ponderada de 4,4 estrelas em 162 análises.</p><p><a href="https://www.class-central.com/mooc/1579/stanford-openedx-statlearning-statistical-learning" rel="noopener">StatLearning: Statistical Learning</a> (Universidade de Stanford): baseado no excelente livro didático, "<a href="https://www.amazon.com.br/Introduction-Statistical-Learning-Applications/dp/1071614177/ref=sr_1_fkmr0_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=15D70PIO4NUXX&amp;keywords=An+Introduction+to+Statistical+Learning%3A+with+Applications+in+R+%28Springer+Texts+in+Statistics&amp;qid=1677176624&amp;sprefix=an+introduction+to+statistical+learning+with+applications+in+r+springer+texts+in+statistics%2Caps%2C706&amp;sr=8-1-fkmr0&amp;ufe=app_do%3Aamzn1.fos.25548f35-0de7-44b3-b28e-0f56f3f96147">An Introduction to Statistical Learning, with Applications in R</a>" e ensinado pelos professores que o escreveram. Os revisores observam que o MOOC não é tão bom quanto o livro, citando exercícios "pouco desafiadores" e vídeos medíocres. Cinco horas por semana durante nove semanas. Gratuito. Tem uma classificação média ponderada de 4,35 estrelas em 84 análises.</p><p><a href="https://www.class-central.com/certificate/machine-learning-specialization" rel="noopener">Machine Learning Specialization</a> (Universidade de Washington/Coursera): grandes cursos, mas as duas últimas aulas (incluindo o projeto final) foram canceladas. Os revisores observam que esta série é mais digerível (leia-se: mais fácil para aqueles sem formação técnica sólida) do que outros cursos de aprendizagem de máquina de ponta (por exemplo, o de Stanford ou o da Caltech). Esteja ciente de que a série está incompleta, sem os sistemas de recomendação, sem aprendizagem profunda e sem um resumo. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 4,31 estrelas em 80 análises.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_fgFqV9nyUKHi7txzgKcW4w.png" class="kg-image" alt="1_fgFqV9nyUKHi7txzgKcW4w" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_fgFqV9nyUKHi7txzgKcW4w.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_fgFqV9nyUKHi7txzgKcW4w.png 800w" sizes="(min-width: 720px) 720px" width="800" height="163" loading="lazy"><figcaption>A Universidade de Washington ensina a <a href="https://www.class-central.com/certificate/machine-learning-specialization" rel="noopener">Machine Learning Specialization</a> na Coursera.</figcaption></figure><p><a href="https://click.linksynergy.com/fs-bin/click?id=SAyYsTvLiGQ&amp;subid=&amp;offerid=323058.1&amp;type=10&amp;u1=medium-career-guide-machine-learning&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Ffrom-0-1-machine-learning%2F" rel="noopener">From 0 to 1: Machine Learning, NLP &amp; Python-Cut to the Chase</a> (Loony Corn/Udemy): "uma abordagem lúcida e breve, mas confiante, sobre as técnicas de aprendizagem de máquina". Ensinado por uma equipe de quatro pessoas com décadas de experiência no setor. Utiliza o Python. O custo varia dependendo dos descontos da Udemy, que são frequentes. Tem uma classificação média ponderada de 4,2 estrelas em 494 análises.</p><p><a href="https://www.class-central.com/mooc/6511/edx-principles-of-machine-learning" rel="noopener">Principles of Machine Learning</a> (Microsoft/edX): utiliza R, Python e a aprendizagem de máquina do Microsoft Azure. Parte do programa do certificado em Ciência de Dados da Microsoft Professional. Três a quatro horas por semana durante seis semanas. Gratuito com um certificado verificado disponível para compra. Tem uma classificação média ponderada de 4,09 estrelas em 11 análises.</p><p><a href="https://www.class-central.com/mooc/5421/futurelearn-big-data-statistical-inference-and-machine-learning" rel="noopener">Big Data: Statistical Inference and Machine Learning</a> (Universidade de Tecnologia de Queensland/Aprendizagem Futura): um breve e agradável curso exploratório de aprendizagem de máquina, com foco em Big Data. Trata de algumas ferramentas, como R, H2O Flow e WEKA. Apenas três semanas de duração, com uma recomendação de duas horas por semana, mas um dos comentários observa que seis horas por semana seriam mais apropriadas. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 4 estrelas em 4 análises.</p><p><a href="https://www.class-central.com/mooc/3556/coursera-genomic-data-science-and-clustering-bioinformatics-v" rel="noopener">Genomic Data Science and Clustering</a> (Bioinformática V) (Universidade da Califórnia, San Diego/Coursera): para aqueles interessados na intersecção entre a informática e a biologia e em como ela representa uma importante fronteira na ciência moderna. Foca no clustering dos dados e na redução da dimensionalidade. Faz parte da especialização em Bioinformática da Universidade da Califórnia/San Diego. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 4 estrelas em 3 análises.</p><p><a href="https://www.class-central.com/mooc/2996/udacity-intro-to-machine-learning" rel="noopener">Intro to Machine Learning</a> (Udacity): prioriza a amplitude do tópico e as ferramentas práticas (em Python) em vez da profundidade e da teoria. Os instrutores, Sebastian Thrun e Katie Malone, tornam essa aula divertida. Consiste em vídeos curtos e questionários seguidos de um miniprojeto para cada aula. Atualmente, faz parte do Nanodegree de Analista de Dados, da Udacity. Tempo estimado de dez semanas. Gratuito. Tem uma classificação média ponderada de 3,95 estrelas em 19 análises.</p><p><a href="https://www.class-central.com/mooc/4354/coursera-machine-learning-for-data-analysis" rel="noopener">Machine Learning for Data Analysis</a> (Universidade Wesleyan/Coursera): uma breve introdução à aprendizagem de máquina e a alguns algoritmos selecionados. Abrange árvores de decisão, florestas aleatórias, regressão de laço e <em>clustering</em> de <em>k-means</em>. Parte da especialização em Análise de Dados e Interpretação, da Wesleyan. Tempo estimado de quatro semanas. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 3,6 estrelas em 5 análises.</p><p><a href="https://www.class-central.com/mooc/6471/edx-programming-with-python-for-data-science" rel="noopener">Programming with Python for Data Science</a> (Microsoft/edX): produzido pela Microsoft em parceria com o Coding Dojo. Utiliza Python. Oito horas por semana durante seis semanas. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 3,46 estrelas em 37 análises.</p><p><a href="https://www.class-central.com/mooc/1026/udacity-machine-learning-for-trading" rel="noopener">Machine Learning for Trading</a> (Georgia Tech/Udacity): foca na aplicação de abordagens probabilísticas de aprendizagem de máquina para a tomada de decisões comerciais. Utiliza o Python. Faz parte do Nanodegree de Engenheiro de Aprendizagem de Máquina, da Udacity, e do OMS (mestrado on-line) da Georgia Tech. Tempo estimado de quatro meses. Gratuito. Tem uma classificação média ponderada de 3,29 estrelas em 14 análises.</p><p><a href="https://www.class-central.com/mooc/1719/coursera-practical-machine-learning" rel="noopener">Practical Machine Learning</a> (Johns Hopkins University/Coursera): uma breve introdução prática a uma série de algoritmos de aprendizagem de máquina. Várias análises de uma ou duas estrelas expressando uma variedade de preocupações. Parte da especialização em ciência de dados da Johns Hopkins University. Quatro a nove horas por semana durante quatro semanas. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 3,11 estrelas em 37 análises.</p><p><a href="https://www.class-central.com/mooc/4912/edx-machine-learning-for-data-science-and-analytics" rel="noopener">Machine Learning for Data Science and Analytics</a> (Universidade Columbia/edX): introduz uma ampla gama de tópicos de aprendizagem de máquina. Algumas análises negativas fortes, com preocupações que incluem as escolhas de conteúdo, falta de tarefas de programação e apresentação pouco inspiradora. Sete a dez horas por semana durante cinco semanas. Gratuito, com um certificado verificado disponível para compra. Tem uma classificação média ponderada de 2,74 estrelas em 36 análises.</p><p><a href="https://www.coursera.org/specializations/recommender-systems" rel="noopener">Recommender Systems Specialization</a> (Universidade de Minnesota/Coursera): forte foco em um tipo específico de aprendizagem de máquina – sistemas de recomendação. Uma especialização de quatro cursos mais um projeto final, que é um estudo de caso. Ensinado usando o LensKit (um kit de ferramentas de código aberto para sistemas de recomendação). Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 2 estrelas em 2 análises.</p><p><a href="https://www.class-central.com/mooc/4238/coursera-machine-learning-with-big-data" rel="noopener">Machine Learning With Big Data</a>(Universidade da Califórnia, San Diego/Coursera): críticas fortes, que destacam instrução e avaliação deficientes. Alguns notaram que levaram apenas horas para completar o curso inteiro. Parte da Especialização em Big Data da UCSD. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 1,86 estrela em 14 análises.</p><p><a href="https://www.class-central.com/mooc/4341/coursera-practical-predictive-analytics-models-and-methods" rel="noopener">Practical Predictive Analytics: Models and Methods</a> (Universidade de Washington/Coursera): uma breve introdução aos conceitos centrais de aprendizagem da máquina. Um dos comentários observou que não havia questionários e que as tarefas não eram desafiadoras. Parte da especialização em Ciência de Dados em escala, da Universidade de Washington. De seis a oito horas por semana durante quatro semanas. Opções gratuitas e pagas disponíveis. Tem uma classificação média ponderada de 1,75 estrelas em 4 análises.</p><p>Os cursos abaixo tiveram uma ou nenhuma revisão desde maio de 2017:</p><p><a href="https://www.class-central.com/mooc/3768/kadenze-machine-learning-for-musicians-and-artists" rel="noopener">Machine Learning for Musicians and Artists</a> (Goldsmiths, Universidade de Londres/Kadenze): único. Os estudantes aprendem algoritmos, ferramentas de software e melhores práticas de aprendizagem de máquina para dar sentido ao gesto humano, ao áudio musical e a outros dados em tempo real. Sete sessões de duração. Opções de auditoria (grátis) e premium ($10 USD por mês) disponíveis. Tem uma análise com 5 estrelas.</p><p><a href="https://www.class-central.com/mooc/6673/coursera-applied-machine-learning-in-python" rel="noopener">Applied Machine Learning in Python</a> (Universidade de Michigan/Coursera): ensinado usando Python e o kit de ferramentas do scikit-learn. Parte da especialização em Ciência de Dados Aplicada com Python. Programado para começar em 29 de maio. Opções gratuitas e pagas disponíveis.</p><p><a href="https://www.class-central.com/mooc/6406/edx-applied-machine-learning" rel="noopener">Applied Machine Learning</a> (Microsoft/edX): ensinado usando várias ferramentas, incluindo Python, R e a aprendizagem de máquina do Microsoft Azure (observação: a Microsoft produz o curso). Inclui laboratórios práticos para reforçar o conteúdo das aulas. Três a quatro horas por semana durante seis semanas. Gratuito com um certificado verificado disponível para compra.</p><p><a href="https://bigdatauniversity.com/courses/machine-learning-with-python/" rel="noopener">Machine Learning with Python</a> (Big Data University): ensinado usando Python. Voltado para iniciantes. Tempo estimado de conclusão de quatro horas. A Big Data University é afiliada à IBM. Gratuito.</p><p><a href="https://bigdatauniversity.com/courses/machine-learning-apache-systemml/" rel="noopener">Machine Learning with Apache SystemML</a> (Big Data University): ensinado utilizando o Apache SystemML, que é uma linguagem de estilo declarativa projetada para a aprendizagem de máquina em larga escala. Tempo estimado de conclusão de oito horas. A Big Data University é afiliada à IBM. Gratuito.</p><p><a href="https://www.class-central.com/mooc/8216/edx-machine-learning-for-data-science" rel="noopener">Machine Learning for Data Science</a> (Universidade da Califórnia, San Diego/edX): não foi lançado até janeiro de 2018. Exemplos de programação e tarefas estão em Python, usando Jupyter Notebooks. Oito horas por semana durante dez semanas. Grauito com um certificado verificado disponível para compra.</p><p><a href="https://www.class-central.com/mooc/8217/edx-introduction-to-analytics-modeling" rel="noopener">Introduction to Analytics Modeling</a>(Georgia Tech/edX): o curso anuncia R como sua principal ferramenta de programação. Cinco a dez horas por semana, durante dez semanas. Gratuito com um certificado verificado disponível para compra.</p><p><a href="https://www.class-central.com/mooc/7645/futurelearn-predictive-analytics-gaining-insights-from-big-data" rel="noopener">Predictive Analytics: Gaining Insights from Big Data</a> (Queensland University of Technology/FutureLearn): breve visão geral de alguns algoritmos. Utiliza a plataforma Vertica Analytics da Hewlett Packard Enterprise como uma ferramenta aplicada. Data de início a ser anunciada. Duas horas por semana ao longo de quatro semanas. Gratuito com um certificado de conclusão disponível para compra.</p><p><a href="https://miriadax.net/web/introduccion-al-machine-learning" rel="noopener">Introducción al Machine Learning</a> (Universitas Telefónica/Miríada X): ensinado em espanhol. Uma introdução à aprendizagem de máquina que abrange a aprendizagem supervisionada e não supervisionada. Um total de vinte horas estimadas em quatro semanas.</p><p><a href="https://www.dataquest.io/path-step/machine-learning" rel="noopener">Machine Learning Path Step</a> (Dataquest): ensinado em Python usando a plataforma interativa do Dataquest no navegador. Múltiplos projetos guiados e um projeto de bônus onde você cria seu próprio sistema de aprendizagem de máquina usando seus próprios dados. Assinatura necessária.</p><p>Os seis cursos a seguir são oferecidos pela <a href="https://www.datacamp.com/courses/topic:machine_learning?tap_a=5644-dce66f&amp;tap_s=93618-a68c98">DataCamp</a>. O estilo de ensino híbrido da DataCamp aproveita a instrução baseada em vídeo e texto, com muitos exemplos através de um editor de código no navegador. Uma assinatura é necessária para o acesso total aos cursos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_eRUPgszpDHzEUpvXhFMeUg.png" class="kg-image" alt="1_eRUPgszpDHzEUpvXhFMeUg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_eRUPgszpDHzEUpvXhFMeUg.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_eRUPgszpDHzEUpvXhFMeUg.png 800w" sizes="(min-width: 720px) 720px" width="800" height="420" loading="lazy"><figcaption>A <a href="https://www.datacamp.com/courses/topic:machine_learning?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">DataCamp</a> oferece vários cursos de aprendizagem de máquina.</figcaption></figure><p><a href="https://www.datacamp.com/courses/introduction-to-machine-learning-with-r?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">Introduction to Machine Learning</a>(DataCamp): abrange algoritmos de classificação, regressão e agrupamento. Utiliza R. Quinze vídeos e 81 exercícios com um tempo estimado de seis horas.</p><p><a href="https://www.datacamp.com/courses/supervised-learning-with-scikit-learn?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">Supervised Learning with scikit-learn</a> (DataCamp): utiliza Python e scikit-learn. Trata de algoritmos de classificação e regressão. Dezessete vídeos e 54 exercícios com um tempo estimado de quatro horas.</p><p><a href="https://www.datacamp.com/courses/unsupervised-learning-in-r?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">Unsupervised Learning in R</a>(DataCamp): fornece uma introdução básica ao <em>clustering</em> e redução da dimensionalidade em R. Dezesseis vídeos e 49 exercícios com um tempo estimado de quatro horas.</p><p><a href="https://www.datacamp.com/courses/machine-learning-toolbox?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">Machine Learning Toolbox</a> (DataCamp): ensina as "grandes ideias" sobre aprendizagem de máquina. Utiliza R. 24 vídeos e 88 exercícios, com um tempo estimado de quatro horas.</p><p><a href="https://www.datacamp.com/courses/machine-learning-with-the-experts-school-budgets?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">Machine Learning with the Experts: School Budgets</a> (DataCamp): um estudo de caso de uma competição de aprendizagem de máquina sobre DrivenData. Envolve a construção de um modelo para classificar automaticamente os itens no orçamento de uma escola. O curso "<a href="https://www.datacamp.com/courses/supervised-learning-with-scikit-learn?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">Supervised Learning with scikit-learn</a>" da DataCamp é um pré-requisito. Quinze vídeos e 51 exercícios com um tempo estimado de quatro horas.</p><p><a href="https://www.datacamp.com/courses/unsupervised-learning-in-python?tap_a=5644-dce66f&amp;tap_s=93618-a68c98" rel="noopener">Unsupervised Learning in Python</a> (DataCamp): trata de uma variedade de algoritmos de aprendizagem não supervisionada usando Python, scikit-learn e scipy. O curso termina com os alunos criando um sistema de recomendação para recomendar músicos populares. Treze vídeos e 52 exercícios com um tempo estimado de quatro horas.</p><p><a href="http://www.cs.cmu.edu/~ninamf/courses/601sp15/index.html" rel="noopener">Machine Learning</a> (Tom Mitchell/Carnegie Mellon University): curso de iniciação à aprendizagem de máquina da Carnegie Mellon. Um pré-requisito para seu segundo curso de pós-graduação, "<a href="https://www.class-central.com/mooc/8509/statistical-machine-learning" rel="noopener">Statistical Machine Learning</a>". Aulas de nível universitário com problemas práticos, tarefas de casa e uma avaliação de meio de semestre (todos com soluções) disponíveis on-line. Também há uma versão de 2011 do curso. A Carnegie Mellon University é uma das melhores escolas de pós-graduação para o estudo de aprendizagem de máquina e tem todo um departamento dedicado à área. Gratuito.</p><p><a href="https://www.class-central.com/mooc/8509/statistical-machine-learning" rel="noopener">Statistical Machine Learning</a> (Larry Wasserman/Carnegie Mellon University): provavelmente, o curso mais avançado deste guia. Um acompanhamento do curso <a href="http://www.cs.cmu.edu/~ninamf/courses/601sp15/index.html" rel="noopener">Machine Learning</a>, da Carnegie Mellon. Aulas de nível universitário com problemas práticos, tarefas de casa e uma avaliação de meio de semestre (todos com soluções) disponíveis on-line. Gratuito.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_umqMeqC5Ch-kR1i4hPBTrw.png" class="kg-image" alt="1_umqMeqC5Ch-kR1i4hPBTrw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/02/1_umqMeqC5Ch-kR1i4hPBTrw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/02/1_umqMeqC5Ch-kR1i4hPBTrw.png 800w" sizes="(min-width: 720px) 720px" width="800" height="74" loading="lazy"><figcaption>A Carnegie Melon University é uma das melhores escolas de pós-graduação para o estudo de aprendizagem de máquina. <a href="http://www.cs.cmu.edu/~ninamf/courses/601sp15/index.html" rel="noopener">Machine Learning</a> e <a href="https://www.class-central.com/mooc/8509/statistical-machine-learning" rel="noopener">Statistical Machine Learning</a> são os cursos disponíveis gratuitamente on-line.</figcaption></figure><p><a href="http://www.cs.ubc.ca/~nando/340-2012/index.php" rel="noopener">Undergraduate Machine Learning</a> (Nando de Freitas/Universidade de British Columbia): um curso de graduação em aprendizagem de máquina. As aulas são filmadas e colocadas no YouTube, com os slides postados no site do curso. As tarefas do curso também são postadas (mas sem as soluções). Nando de Freitas é agora professor em tempo integral na Universidade de Oxford e recebe elogios por sua capacidade de ensino em vários fóruns. Versão para pós-graduandos disponível (veja abaixo).</p><p><a href="http://www.cs.ubc.ca/~nando/540-2013/lectures.html" rel="noopener">Machine Learning</a> (Nando de Freitas/Universidade de British Columbia): um curso de pós-graduação em aprendizagem de máquina. Os comentários sobre o curso de graduação de Nando de Freitas (acima) também se aplicam aqui.</p><h3 id="para-encerrar"><strong>Para encerrar</strong></h3><p>Este é o quinto de uma série de seis artigos que tratam dos melhores cursos on-line para se lançar no campo da ciência dos dados. Tratamos de programação no <a href="https://freecodecamp.org/news/if-you-want-to-learn-data-science-start-with-one-of-these-programming-classes-fb694ffe780c#.fhrn45v3c">primeiro artigo</a> (texto em inglês), estatística e probabilidade no <a href="https://freecodecamp.org/news/if-you-want-to-learn-data-science-take-a-few-of-these-statistics-classes-9bbabab098b9#.p7pac546r">segundo artigo</a> (texto em inglês), introdução a ciência de dados no <a href="https://www.freecodecamp.org/portuguese/news/classifiquei-cada-curso-de-introducao-a-ciencia-de-dados-na-internet-com-base-em-milhares-de-avaliacoes/">terceiro artigo</a> e visualização de dados no <a href="https://freecodecamp.org/news/an-overview-of-every-data-visualization-course-on-the-internet-9ccf24ea9c9b">quarto</a> (texto em inglês).</p><p>A parte final desta série será um resumo desses artigos, juntamente aos melhores cursos on-line para outros tópicos-chave, tais como discussão de dados, bancos de dados e até mesmo engenharia de software.</p><p>Se você estiver procurando uma lista completa de cursos on-line de Ciência de dados, você pode encontrá-los na página sobre <a href="https://www.class-central.com/subject/data-science" rel="noopener">Data Science and Big Data</a> da Class Central.</p><p>Se você gostou de ler este texto, confira alguns outros artigos da <a href="https://www.class-central.com/">Class Central</a> (em inglês):</p><p><a href="https://www.freecodecamp.org/news/ivy-league-free-online-courses-a0d7ae675869/"><strong><strong>Here are 250 Ivy League courses you can take online right now for free</strong></strong></a></p><p><a href="https://www.freecodecamp.org/news/the-data-dont-lie-here-are-the-50-best-free-online-university-courses-of-all-time-b2d9a64edfac/"><strong><strong>The 50 best free online university courses according to data</strong></strong></a></p><p><em>Esta é uma versão condensada do <a href="https://www.class-central.com/report/best-machine-learning-courses/">artigo original</a>, publicado na Class Central, onde o autor incluiu um programa detalhado dos cursos.</em></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como passar na entrevista de programação – Dicas que me ajudaram a obter ofertas de emprego no Google, Airbnb e na Dropbox ]]>
                </title>
                <description>
                    <![CDATA[ Em 2017, passei por algumas entrevistas de programação e recebi ofertas de várias grandes empresas de tecnologia. Foi naquele momento que decidi compartilhar o que tinha aprendido neste artigo. Acabo de atualizá-lo para este ano para que seja superútil e relevante se você estiver procurando emprego agora. Apesar de ter ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-passar-na-entrevista-de-programacao-dicas-que-me-ajudaram-a-obter-ofertas-de-emprego-no-google-airbnb-e-na-dropbox/</link>
                <guid isPermaLink="false">63870e25d7295905e93497cf</guid>
                
                    <category>
                        <![CDATA[ Desenvolvimento para a Web ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Wed, 11 Jan 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/1_Qf9fEs5XdOEQiWX3R6R6ww.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/coding-interviews-for-dummies-5e048933b82b/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Rock the Coding Interview – Tips That Helped Me Land Job Offers from Google, Airbnb, and Dropbox</a>
      </p><p>Em 2017, passei por algumas entrevistas de programação e recebi ofertas de várias grandes empresas de tecnologia. Foi naquele momento que decidi compartilhar o que tinha aprendido neste artigo.</p><p>Acabo de atualizá-lo para este ano para que seja superútil e relevante se você estiver procurando emprego agora.</p><p>Apesar de ter notas decentes tanto na minha disciplina básica de algoritmos, quanto na minha disciplina de estruturas de dados no curso de Ciência da Computação na universidade, estremeço ao pensar em passar por uma entrevista de programação que se concentre em algoritmos.</p><p>Assim, passei os últimos três meses descobrindo como melhorar minhas habilidades em programação para entrevistas e, no fim, recebi ofertas de grandes empresas de tecnologia, como <strong>Google</strong>, <strong>Facebook</strong>, <strong>Airbnb</strong>, <strong>Lyft</strong>, <strong>Dropbox</strong> e muitas outras.</p><p>Neste artigo, compartilharei as ideias e dicas que recebi ao longo do caminho. Candidatos experientes também podem esperar perguntas sobre design de sistemas, mas isso está fora do escopo deste artigo.</p><p>Muitos dos conceitos algorítmicos testados em entrevistas de programação não são aquilo que costumo usar no trabalho, onde sou um engenheiro de <em>front-end</em> (web). Naturalmente, me esqueci um pouco desses algoritmos e estruturas de dados, que aprendi principalmente durante o primeiro e o segundo anos da minha faculdade.</p><p>É estressante ter que produzir código (funcional) em uma entrevista enquanto alguém examina cada toque no teclado que você faz. O pior é que, como entrevistado, você é encorajado a comunicar seu processo de pensamento em voz alta ao entrevistador.</p><p>Eu costumava pensar que ser capaz de pensar, programar e comunicar simultaneamente era um feito impossível, até que percebi que a maioria das pessoas simplesmente não é boa em entrevistas de programação quando começam. Ser entrevistado é uma habilidade em que se pode melhorar estudando, preparando-se e praticando para isso.</p><p>Minha busca de emprego recente me levou a uma jornada para melhorar minhas habilidades para as entrevistas de programação. Os engenheiros de <em>front-end</em> gostam de se queixar de como o atual processo de contratação é ruim, pois as entrevistas técnicas podem incluir habilidades não relacionadas ao desenvolvimento de <em>front-end</em>. Por exemplo, escrever um algoritmo de resolução de labirintos e mesclar duas listas ordenadas de números. Como engenheiro de <em>front-end</em>, eu entendo bem o motivo da reclamação.</p><p>O <em>front-end</em> é um domínio especializado, onde os engenheiros têm que se preocupar com muitas questões relacionadas às compatibilidades do navegador, o Modelo de Objeto do Documento (DOM - Document Object Model), desempenho do JavaScript, layouts do CSS e assim por diante. É incomum para os engenheiros de <em>front-end </em>implementar alguns dos complexos algoritmos testados em entrevistas.</p><blockquote><strong>Em empresas como Facebook e Google, as pessoas são engenheiras de software em primeiro lugar, especialistas de domínio em segundo.</strong></blockquote><p>Infelizmente, as regras são estabelecidas pelas empresas, não pelos candidatos. Há uma grande ênfase nos conceitos gerais da informática, como algoritmos, padrões de design e estruturas de dados – habilidades essenciais que um bom engenheiro de software deve possuir. Se você quer o trabalho, você tem que jogar de acordo com as regras estabelecidas pelos mestres do jogo – e melhorar suas habilidades para as entrevistas de programação!</p><p>Este artigo está estruturado nas duas seções seguintes. Sinta-se à vontade para pular para a seção que interessa a você.</p><ul><li>O formato das entrevistas de programação e como se preparar para elas.</li><li>Dicas úteis para cada tópico de algoritmos (arrays, árvores, programação dinâmica etc.), juntamente com perguntas práticas recomendadas pelo LeetCode para rever os conceitos centrais e melhorar nesses tópicos.</li></ul><p>O conteúdo deste artigo <a href="https://www.techinterviewhandbook.org/">pode ser encontrado aqui</a> (em inglês). Lá, farei atualizações quando necessário.</p><p>Se você está interessado no conteúdo de <em>front-end</em>, confira meu manual de entrevistas para <em>front-end</em> <a href="https://www.frontendinterviewhandbook.com/">aqui</a> (em inglês).</p><h2 id="escolhendo-uma-linguagem-de-programa-o"><strong>Escolhendo uma linguagem de programação</strong></h2><p>Antes de mais nada, você precisa escolher uma linguagem de programação para sua entrevista de programação algorítmica.</p><p>A maioria das empresas permitirá que você programe na linguagem de sua escolha. A única exceção que eu conheço é o Google. Lá, é permitido que seus candidatos escolham apenas entre Java, C++, Python, Go ou JavaScript.</p><p>Na maioria das vezes, recomendo o uso de uma linguagem com a qual você esteja extremamente familiarizado, em vez de uma linguagem que é nova para você, mas que a empresa utiliza amplamente.</p><p>Há algumas linguagens que são mais adequadas do que outras para as entrevistas de programação. Também há algumas outras que você vai querer evitar, com certeza.</p><p>A partir da minha experiência como entrevistador, a maioria dos candidatos escolhe Python ou Java. Outras linguagens comumente selecionadas incluem JavaScript, Ruby e C++. Eu evitaria absolutamente linguagens de mais baixo nível, como o C ou o Go, simplesmente porque elas não possuem funções de biblioteca padrão e estruturas de dados.</p><p>Pessoalmente, o Python é normalmente a minha escolha para os algoritmos de programação durante as entrevistas. Ele é sucinto e tem uma enorme biblioteca de funções e estruturas de dados.</p><p>Uma das principais razões que me faz recomendar o Python é o fato de ele usar APIs consistentes, que operam em diferentes estruturas de dados, tais como <code>len()</code>, <code>for ... in ...</code> e notação de corte (do inglês, <em>slicing</em>) em sequências (strings, listas e tuplas). Obter o último elemento em uma sequência é <code>arr[-1]</code> e revertê-lo é simplesmente <code>arr[::-1]</code>. Você pode conseguir muito com pouca sintaxe em Python.</p><p>O Java também é uma escolha decente. Como, no entanto, você terá que declarar constantemente os tipos em seu código, isso significa digitar mais. Isso diminuirá a velocidade na qual você programa e digita. Essa questão fica mais aparente quando você tiver que escrever em um quadro branco durante entrevistas no local.</p><p>As razões para escolher ou não escolher C++ são similares às de Java. No fim, Python, Java, e C++ são escolhas decentes. Se você está usando Java há algum tempo e não tem tempo para se familiarizar com outra linguagem, recomendo que se mantenha fiel ao Java em vez de pegar o Python do zero. Isto o ajudará a evitar de ter que usar uma linguagem para o trabalho e outra para entrevistas. A maior parte do tempo, o que trava é o pensamento, não a escrita.</p><p>Uma exceção à convenção de permitir que o candidato "escolha a linguagem de programação que quiser" é quando a entrevista é para um cargo específico de domínio, como funções de engenheiro de <em>front-end</em>, iOS ou Android. Você precisa estar familiarizado com algoritmos de programação em JavaScript, Objective-C, Swift e Java, respectivamente.</p><p>Se você precisar usar uma estrutura de dados que a linguagem não suporte, como uma fila ou pilha em JavaScript, pergunte ao entrevistador se você pode assumir que tem uma estrutura de dados que implementa certos métodos com complexidades de tempo especificadas. Se a implementação dessa estrutura de dados não for crucial para a solução do problema, o entrevistador normalmente a permitirá.</p><p>Na realidade, estar ciente das estruturas de dados existentes e selecionar as estruturas apropriadas para resolver o problema em questão é mais importante do que conhecer os intrincados detalhes de implementação.</p><h2 id="revise-sua-ci-ncia-da-computa-o-b-sica">Revise sua Ciência da Computação básica</h2><p>Se você estiver fora da faculdade há algum tempo, é altamente aconselhável rever os fundamentos de computação. Eu prefiro revisar enquanto pratico. Eu revejo minhas anotações da faculdade e reviso os vários algoritmos enquanto trabalho nos problemas de algoritmos do LeetCode e do Cracking the Coding Interview.</p><p>Se você estiver interessado em como as estruturas de dados são implementadas, confira <a href="https://github.com/yangshun/lago">Lago</a>, um repositório do GitHub contendo estruturas de dados e exemplos de Algoritmos em JavaScript.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/lago.png" class="kg-image" alt="lago" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/01/lago.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/01/lago.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/01/lago.png 1200w" sizes="(min-width: 720px) 720px" width="1200" height="600" loading="lazy"><figcaption><a href="https://github.com/yangshun/lago">GitHub - yangshun/lago: 📕 Biblioteca de Algoritmos e Estruturas de Dados em TypeScript</a></figcaption></figure><h2 id="dom-nio-atrav-s-da-pr-tica"><strong>Domínio através da prática</strong></h2><p>Em seguida, adquira familiaridade e domínio dos algoritmos e estruturas de dados em sua linguagem de programação escolhida.</p><p>Pratique e resolva questões de algoritmos na linguagem de sua escolha. Embora o Cracking the Coding Interview seja um bom recurso, prefiro resolver problemas digitando o código, deixando-o rodar e obtendo feedback instantâneo.</p><p>Há vários juízes on-line, tais como o <a href="https://leetcode.com/">LeetCode</a>, o <a href="https://www.hackerrank.com/">HackerRank</a> e o <a href="http://codeforces.com/">CodeForces</a> para você praticar perguntas on-line e se acostumar a linguagem. Pela minha experiência, as perguntas do LeetCode são mais parecidas com as perguntas feitas em entrevistas. As perguntas do HackerRank e do CodeForces são mais parecidas com as perguntas da programação competitiva.</p><p>Se você praticar perguntas suficientes do LeetCode, há uma boa chance de que você veja ou complete uma das suas perguntas reais de entrevista (ou alguma variante dela).</p><p>Aprenda e compreenda as complexidades de tempo e de espaço das operações comuns na sua linguagem escolhida. Para Python, esta <a href="https://wiki.python.org/moin/TimeComplexity">página</a> virá a calhar. Aprenda também sobre o algoritmo de ordenação subjacente a ser usado na função <code>sort()</code> da linguagem e as suas complexidades de tempo e de espaço (em Python é o <a href="https://pt.wikipedia.org/wiki/Timsort">TimSort</a>, que é um híbrido).</p><p>Depois de completar uma pergunta do LeetCode, normalmente acrescento as complexidades de tempo e espaço do código escrito como comentários acima do corpo da função. Utilizo os comentários para me lembrar de comunicar a análise do algoritmo após ter completado a implementação.</p><p>Leia sobre o estilo de programação recomendado para a sua linguagem e mantenha-se fiel a ele. Se escolher Python, consulte o <a href="https://pep8.org/">Guia de Estilo PEP 8</a> (em inglês). Se escolher Java, consulte o <a href="https://google.github.io/styleguide/javaguide.html">Guia de Estilo de Java do Google</a> (em inglês).</p><p>Aprenda e esteja familiarizado com as armadilhas e problemas comuns da linguagem. Se os apontar durante a entrevista e se evitar cair neles, ganhará pontos a mais e impressionará o entrevistador, independentemente de o entrevistador estar familiarizado com a linguagem ou não.</p><p>Obtenha uma ampla exposição a questões de vários tópicos. Na segunda metade do artigo, menciono tópicos de algoritmos e as questões úteis para a prática de cada tópico. Faça cerca de 100 a 200 perguntas do LeetCode e você deverá se sair bem.</p><p>Se preferir cursos onde a aprendizagem seja mais estruturada, aqui ficam algumas recomendações. <strong>De modo algum é obrigatório fazer cursos on-line para passar em entrevistas.</strong></p><ul><li>O <a href="https://algo.monster/">AlgoMonster</a> visa ajudá-lo a passar na entrevista técnica no <strong>mais curto espaço de tempo possível</strong>. Criado por engenheiros do Google, o AlgoMonster utiliza uma abordagem baseada em dados para ensinar os padrões de perguntas-chave mais úteis e tem conteúdos para ajudar a rever rapidamente algoritmos e estruturas de dados básicos. O melhor de tudo é que o AlgoMonster não é baseado em assinaturas – pague uma taxa única e obtenha <strong>acesso vitalício</strong>.</li><li><a href="https://www.educative.io/courses/grokking-the-coding-interview">Grokking the Coding Interview: Patterns for Coding Questions</a>, da Educative, expande as questões práticas recomendadas neste artigo, mas aborda a prática a partir de uma perspectiva de padrão de perguntas, que é uma abordagem com a qual também concordo para a aprendizagem e com a qual me habituei pessoalmente a melhorar na programação de entrevistas. O curso permite praticar perguntas selecionadas em Java, Python, C++, JavaScript e também fornece exemplos de soluções nessas linguagens. Aprenda e compreenda os padrões em vez de memorizar as respostas.</li></ul><p>Logicamente, pratique, pratique e pratique um pouco mais!</p><h2 id="fases-de-uma-entrevista-de-programa-o"><strong>Fases de uma entrevista de </strong>program<strong>ação</strong></h2><p>Parabéns! Você está pronto para pôr as suas capacidades em prática! Em uma entrevista de programação, será feita uma pergunta técnica pelo entrevistador. Você escreverá o código em tempo real, em um editor colaborativo (tela do telefone) ou em um quadro branco (no local) e terá 30 a 45 minutos para resolver o problema. É aqui que a verdadeira diversão começa!</p><p>O seu entrevistador procurará ver se você preenche os requisitos para o cargo. Cabe a você mostrar para ele que possui as competências necessárias. Inicialmente, pode parecer estranho falar enquanto programa, já que a maioria dos programadores não tem o hábito de explicar em voz alta os seus pensamentos enquanto escrevem o código.</p><p>No entanto, é difícil para o entrevistador saber o que você está pensando simplesmente olhando para o seu código. Se comunicar a sua abordagem ao entrevistador mesmo antes de começar a programar, pode validar a sua abordagem com eles. Dessa forma, os dois podem chegar a acordo sobre uma abordagem aceitável.</p><h2 id="prepara-o-para-uma-entrevista-remota"><strong>Preparação para uma entrevista remota</strong></h2><p>Para telas de telefones e entrevistas remotas, tenha à disposição um papel e uma caneta ou lápis para fazer anotações ou diagramas. Se for feita uma pergunta sobre árvores e gráficos, geralmente ajuda desenhar exemplos da estrutura de dados.</p><p>Use fones de ouvido. Certifique-se de que se encontra em um ambiente calmo. Não queira segurar o telefone com uma mão e escrever com a outra. Tente evitar o uso de alto-falantes. Se o feedback for ruim, a comunicação fica mais difícil. Ter que repetir apenas resultará em perda de tempo valioso.</p><h2 id="o-que-fazer-quando-voc-receber-a-pergunta"><strong>O que fazer quando você receber a pergunta</strong></h2><p>Muitos candidatos começam a programar assim que ouvem a pergunta. Isso geralmente é um grande erro. Primeiro, reserve um momento e repita a pergunta para o entrevistador para ter certeza de que você entendeu a pergunta. Se você tiver entendido mal a pergunta, o entrevistador poderá esclarecê-la.</p><p>Sempre busque esclarecimento sobre a questão ao ouvi-la, mesmo que você ache que é clara. Você pode descobrir que escapou alguma coisa. Isso também permite ao entrevistador saber que você está atento aos detalhes.</p><p>Considere fazer as seguintes perguntas:</p><ul><li>Qual é o tamanho da entrada?</li><li>Qual é o tamanho do intervalo de valores?</li><li>Que tipo de valores existem? Existem números negativos? Pontos flutuantes? Haverá entradas vazias?</li><li>Há duplicatas dentro da entrada?</li><li>Quais são alguns casos extremos da entrada?</li><li>Como a entrada é armazenada? Se você receber um dicionário de palavras, é uma lista de strings ou um <em><a href="https://pt.wikipedia.org/wiki/Trie">trie</a></em>?</li></ul><p>Depois de ter esclarecido suficientemente o escopo e a intenção do problema, explique ao entrevistador sua abordagem de alto nível, mesmo que seja uma solução ingênua. Se você estiver preso, considere várias abordagens e explique em voz alta porque elas podem ou não funcionar. Às vezes, seu entrevistador pode deixar passar dicas que o levarão no caminho certo.</p><p>Comece com uma abordagem de força bruta. Comunique-a ao entrevistador. Explique as complexidades de tempo e espaço e esclareça o motivo de tentar a força bruta é ruim. É improvável que a abordagem de força bruta seja aquela que você utilizará em programação. Neste ponto, o entrevistador normalmente fará a temida pergunta "Podemos fazer melhor?". Isso significa que estão procurando por uma abordagem mais otimizada.</p><p>Essa é geralmente a parte mais difícil da entrevista. Em geral, procure por trabalhos repetidos e tente otimizá-los, potencialmente armazenando o resultado calculado em algum lugar. Consulte-o mais tarde, em vez de calculá-lo novamente. A seguir, forneço algumas dicas para abordar detalhadamente questões específicas do tópico.</p><p>Só comece a programar depois que você e seu entrevistador tiverem concordado em uma abordagem e que você tenha recebido um sinal positivo para seguir em frente.</p><h2 id="come-ando-a-programar"><strong>Começando a </strong>program<strong>ar</strong></h2><p>Use um bom estilo para escrever seu código. Ler código escrito por outros geralmente não é uma tarefa agradável. Ler código horrivelmente formatado escrito por outros é ainda pior. Seu objetivo é fazer seu entrevistador entender seu código para que possa avaliar rapidamente se seu código faz o que se supõe que faça e se resolve um determinado problema.</p><p>Use nomes de variáveis claros e evite nomes que sejam letras únicas, a menos que sejam para a iteração. Entretanto, se você estiver programando em um quadro branco, evite usar nomes extensos de variáveis. Isso reduz a quantidade de escrita que você terá que fazer.</p><p>Sempre explique ao entrevistador o que você está escrevendo ou digitando. Não se trata de ler, textualmente, para o entrevistador o código que você está produzindo. Fale sobre a seção do código que você está implementando atualmente em nível superior. Explique por que ele é escrito assim e o que está tentando alcançar.</p><p>Ao copiar e colar em código, considere se é necessário. Às vezes, é; às vezes, não é. Se você se encontrar copiando e colando um grande pedaço de código abrangendo várias linhas, provavelmente é um indicador de que você pode reestruturar o código, extraindo essas linhas em uma função. Se for apenas uma única linha que você copiou, geralmente está bem.</p><p>Entretanto, lembre-se de alterar as respectivas variáveis em sua linha de código copiada, onde for relevante. Erros de cópia e colagem são uma fonte comum de <em>bugs</em>, mesmo na programação do dia a dia!</p><h2 id="ap-s-a-programa-o"><strong>Após a </strong>program<strong>ação</strong></h2><p>Depois de terminar de programar, não anuncie imediatamente ao entrevistador que você está pronto. Na maioria dos casos, seu código geralmente não está perfeito. Ele pode conter <em>bugs </em>ou erros de sintaxe. O que você precisa fazer é revisar seu código.</p><p>Primeiro, olhe seu código do início ao fim. Olhe para ele como se fosse escrito por outra pessoa, como se você o estivesse vendo pela primeira vez e tentando detectar erros nele. Isso é exatamente o que seu entrevistador estará fazendo. Revise e corrija quaisquer problemas que você possa encontrar.</p><p>Em seguida, apresente pequenos casos de teste e execute o código passo a passo (não seu algoritmo) com essas amostras de entrada.</p><p>Os entrevistadores gostam quando você lê suas mentes. O que eles costumam fazer depois que você termina de programar é fazer você escrever testes. É uma grande vantagem se você escrever testes para seu código antes mesmo que eles o peçam para fazer isso. Você deve estar emulando um depurador ao passar por seu código. Anote ou diga a eles os valores de certas variáveis enquanto você percorre com o entrevistador as linhas de código.</p><p>Se houver grandes pedaços duplicados de código na sua solução, reestruture o código para mostrar ao entrevistador que você valoriza a programação de qualidade. Além disso, procure lugares onde você possa fazer uma <a href="https://pt.wikipedia.org/wiki/Avalia%C3%A7%C3%A3o_de_curto-circuito">avaliação de curto-circuito</a>.</p><p>Por fim, forneça as complexidades de tempo e espaço de seu código e explique por que ele é assim. Você pode fazer anotações em partes do seu código com suas várias complexidades de tempo e espaço para demonstrar sua compreensão do código. Você pode até mesmo fornecer as APIs de sua linguagem de programação escolhida. Explique quaisquer <em>trade-offs</em> na sua abordagem atual em comparação com abordagens alternativas, possivelmente em termos de tempo e espaço.</p><p>Se seu entrevistador estiver satisfeito com a solução, a entrevista geralmente termina aqui. Também é comum que o entrevistador faça perguntas de extensão, como, por exemplo, sobre como você lidaria com o problema se toda a entrada for muito grande para caber na memória, ou se a entrada chegar como uma <em>stream</em>. Essa é uma pergunta posterior comum no Google, onde eles se preocupam muito com a escala.</p><p>A resposta é geralmente uma abordagem de dividir e conquistar – realizar o processamento distribuído dos dados e somente ler certas partes da entrada do disco para a memória, gravar a saída de volta para o disco e combiná-los mais tarde.</p><h2 id="pr-tica-com-entrevistas-simuladas"><strong>Prática com entrevistas simuladas</strong></h2><p>Os passos mencionados acima podem ser repetidamente ensaiados até que você os tenha interiorizado completamente e eles se tornem normais para você. Uma boa maneira de praticar é fazer uma parceria com um amigo e revezar nas entrevistas um com o outro.</p><p>Um grande recurso para a preparação de entrevistas de programação é o <a href="https://iio.sh/r/DMCa">interview</a><a href="https://iio.sh/r/DMCa">.io</a>. Essa plataforma oferece entrevistas práticas gratuitas e anônimas com engenheiros do Google e do Facebook, que podem levar a empregos e estágios reais.</p><p>Em virtude de ser anônimo durante a entrevista, o processo de entrevista inclusiva é imparcial e de baixo risco. No final da entrevista, tanto o entrevistador quanto o entrevistado podem dar feedback um ao outro com o objetivo de ajudar um ao outro a melhorar.</p><p>Sair-se bem nas entrevistas simuladas desbloqueará a página de empregos para os candidatos e permitirá que eles marquem entrevistas (também anônimas) com empresas de ponta, como Uber, Lyft, Quora, Asana, entre outras. Para aqueles que são novatos nas entrevistas de programação, uma entrevista demonstrativa pode ser visualizada <a href="https://start.interviewing.io/interview/9hV9r4HEONf9/replay">neste site</a>. Observe que o site exige que os usuários façam o registro.</p><p>Já usei a interviewing.io, tanto como entrevistador quanto como entrevistado. A experiência foi ótima. <a href="https://www.freecodecamp.org/news/coding-interviews-for-dummies-5e048933b82b/undefined">Aline Lerner</a>, a CEO e cofundadora do interviewing.io, e sua equipe são apaixonados por revolucionar o processo de entrevistas de programação e por ajudar os candidatos a melhorar suas habilidades de entrevista.</p><p>Ela também publicou uma série de artigos relacionados às entrevistas de programação no <a href="http://blog.interviewing.io/">blog interviewing.io</a>. Recomendo inscrever-se o mais cedo possível no interviewing.io, mesmo que ele esteja em estágio beta, para aumentar a probabilidade de receber um convite.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/01/image-58.png" class="kg-image" alt="image-58" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/01/image-58.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/01/image-58.png 800w" width="800" height="495" loading="lazy"></figure><p>Outra plataforma que permite praticar entrevistas de programação é a <a href="https://pramp.com/">Pramp</a>. Enquanto a interview.io combina potenciais candidatos a empregos com entrevistadores experientes em programação, a Pramp adota uma abordagem diferente. A Pramp combina você com outro colega que também é um candidato a emprego. Os dois se revezam assumindo as funções de entrevistador e entrevistado. A Pramp também prepara perguntas e fornece soluções e dicas para orientar o entrevistado.</p><h2 id="v-em-frente-e-conquiste"><strong>Vá em frente e conquiste</strong></h2><p>Depois de fazer uma quantidade razoável de perguntas no LeetCode e de ter prática suficiente em entrevistas simuladas, vá em frente e ponha à prova suas novas habilidades de entrevista.</p><p>Inscreva-se em suas empresas favoritas ou, melhor ainda, obtenha indicações de seus amigos que trabalham para essas empresas. As indicações tendem a ser notadas mais cedo e a ter uma taxa de resposta mais rápida do que se você se candidatar sem uma indicação. Boa sorte!</p><h2 id="dicas-pr-ticas-para-quest-es-de-programa-o"><strong>Dicas práticas para questões de </strong>program<strong>ação</strong></h2><p>Esta seção mergulha profundamente em dicas práticas para tópicos específicos de algoritmos e estruturas de dados que aparecem frequentemente em questões de programação. Muitas questões de algoritmos envolvem técnicas que podem ser aplicadas a questões de natureza similar.</p><p>Quanto mais técnicas você tiver em seu arsenal, maiores serão suas chances de passar na entrevista. Para cada tópico, há também uma lista de perguntas recomendadas, que é valiosa para dominar os conceitos centrais. Algumas das perguntas só estão disponíveis com uma assinatura paga do LeetCode, que, na minha opinião, vale o dinheiro se você conseguir um emprego.</p><h2 id="dicas-gerais"><strong>Dicas gerais</strong></h2><p>Valide sempre a entrada em primeiro lugar. Verifique se as entradas são inválidas, vazias, negativas ou diferentes. Nunca assuma que são dados parâmetros válidos. Como alternativa, esclareça com o entrevistador se você pode assumir que a entrada é válida (geralmente, sim), o que pode poupar seu tempo de escrever o código que faz a validação da entrada.</p><p>Há algum requerimento de complexidade de tempo e espaço ou restrições?</p><p>Verificar a existência de <a href="https://en.wikipedia.org/wiki/Off-by-one_error">erros </a><a href="https://en.wikipedia.org/wiki/Off-by-one_error"><em>off-by-one</em></a> (texto em inglês).</p><p>Em linguagens onde não há coerção automática de tipo, verifique se a concatenação de valores é do mesmo tipo: <code>int</code>, <code>str</code> e <code>list</code>.</p><p>Depois de terminar seu código, use alguns exemplos de entradas para testar sua solução.</p><p>O algoritmo deve ser executado várias vezes, talvez em um servidor da web? Em caso positivo, a entrada pode provavelmente ser pré-processada para melhorar a eficiência em cada chamada à API.</p><p>Use uma mistura dos paradigmas de programação funcional e imperativa:</p><ul><li>Escreva funções puras com a maior frequência possível.</li><li>Use funções puras porque são mais fáceis de pensar a respeito e podem ajudar a reduzir erros em sua implementação.</li><li>Evite a alteração dos parâmetros passados para sua função, especialmente se eles forem passados por referência, a menos que você esteja seguro do que está fazendo.</li><li>Atinja um equilíbrio entre precisão e eficiência. Use a quantidade certa de código funcional e imperativo, quando apropriado. A programação funcional é normalmente cara em termos de complexidade espacial devido à não mutação e à alocação repetida de novos objetos. Por outro lado, o código imperativo é mais rápido porque você opera com objetos existentes.</li><li>Evite confiar em variáveis globais mutáveis. As variáveis globais introduzem o estado.</li><li>Certifique-se de que você não mudará acidentalmente as variáveis globais, especialmente se você tiver que confiar nelas.</li></ul><p>Geralmente, para melhorar a velocidade de um programa, podemos escolher entre usar uma estrutura de dados ou um algoritmo apropriado ou usar mais memória. É uma troca clássica de espaço e tempo.</p><p>As estruturas de dados são suas armas. Escolher a arma certa para a batalha certa é a chave para a vitória. Conheça os pontos fortes de cada estrutura de dados e a complexidade de tempo para suas várias operações.</p><p>As estruturas de dados podem ser aumentadas para alcançar uma complexidade de tempo eficiente através de diferentes operações. Por exemplo, um HashMap pode ser usado juntamente com uma lista duplamente vinculada para alcançar a complexidade de tempo O(1) tanto para a operação de <code>get</code> como para a de <code>put</code> em um <a href="https://leetcode.com/problems/lru-cache/">cache LRU</a> (em inglês, onde LRU significa "menos recentemente usado").</p><p>Os HashMaps são provavelmente a estrutura de dados mais comumente usada para questões de algoritmos. Se você estiver preso a uma pergunta, seu último recurso pode ser enumerar através das possíveis estruturas de dados (felizmente não existem tantas) e considerar se cada uma delas pode ser aplicada ao problema. Isto tem funcionado para mim às vezes.</p><p>Se você estiver fazendo coisas apressadamente em seu código, declare isso em voz alta ao seu entrevistador e explique a ele o que você faria fora de um ambiente de entrevista (sem restrições de tempo). Por exemplo, explique que você escreveria uma <em>regex </em>para fazer o <em>parsing </em>de uma string em vez de usar <code>split</code>, que não cobre todos os casos.</p><h2 id="sequ-ncia"><strong>Sequência</strong></h2><h3 id="observa-es"><strong>Observações</strong></h3><p>Arrays e strings são considerados sequenciais (uma string é uma sequência de caracteres). Há dicas para lidar tanto com arrays quanto com strings que serão abordadas aqui.</p><p>Há valores duplicados na sequência? Eles afetariam a resposta?</p><p>Verifique a sequência fora dos limites.</p><p>Esteja atento ao fatiamento (do inglês, <em>slicing</em>) ou à concatenação de sequências em seu código. Tipicamente, o fatiamento e as sequências concatenadas requerem tempo O(n). Use índices de início e fim para demarcar um subarray ou uma substring sempre que possível.</p><p>Às vezes, você percorre a sequência a partir do lado direito em vez do lado esquerdo.</p><p>Dominar a <a href="https://discuss.leetcode.com/topic/30941/here-is-a-10-line-template-that-can-solve-most-substring-problems">técnica de janela deslizante</a> (texto em inglês) que se aplica a muitos problemas de substring ou subarray.</p><p>Quando são dadas duas sequências para processar, é comum ter um índice por sequência a ser percorrida. Por exemplo, usamos a mesma abordagem para unir dois arrays ordenados.</p><h3 id="casos-lim-trofes"><strong>Casos limítrofes</strong></h3><ul><li>Sequência vazia</li><li>Sequência com 1 ou 2 elementos</li><li>Sequência com elementos repetidos</li></ul><h2 id="array"><strong>Array</strong></h2><h3 id="observa-es-1"><strong>Observações</strong></h3><p>O array é ordenado ou parcialmente ordenado? Se for, alguma forma de busca binária deve ser possível. Isto geralmente significa que o entrevistador está procurando uma solução que seja mais rápida do que o O(n).</p><p>Você pode ordenar o array? Às vezes, ordenar o array primeiro pode simplificar significativamente o problema. Certifique-se de que a ordem dos elementos do array não precisa ser preservada antes de tentar ordená-lo.</p><p>Para perguntas onde a soma ou a multiplicação de um subarray está envolvida, a pré-computação usando hashing ou um prefixo, soma de sufixos ou produto pode ser útil.</p><p>Se você receber uma sequência e o entrevistador pedir espaço O(1), talvez seja possível usar o próprio array como uma tabela de hash. Por exemplo, se o array tiver valores apenas de 1 a N, onde N é o comprimento do array, deixe negativo o valor naquele índice (menos um) para indicar a presença daquele número.</p><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode-"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/two-sum/">Duas somas</a></li><li><a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/">Melhor hora para comprar e vender ações</a></li><li><a href="https://leetcode.com/problems/contains-duplicate/">Contém duplicata</a></li><li><a href="https://leetcode.com/problems/product-of-array-except-self/">Produto do Array Exceto Self</a></li><li><a href="https://leetcode.com/problems/maximum-subarray/">Subarray máximo</a></li><li><a href="https://leetcode.com/problems/maximum-product-subarray/">Subarray máximo do produto</a></li><li><a href="https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/">Encontrar o mínimo em um array ordenado e girado</a></li><li><a href="https://leetcode.com/problems/search-in-rotated-sorted-array/">Busca em um array ordenado e girado</a></li><li><a href="https://leetcode.com/problems/3sum/">Soma3</a></li><li><a href="https://leetcode.com/problems/container-with-most-water/">Contêiner com mais água</a></li></ul><h2 id="bin-rio"><strong>Binário</strong></h2><h3 id="links-de-estudo"><strong>Links de estudo</strong></h3><ul><li><a href="https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa">Bits, bytes, construindo com binário</a> (em inglês)</li></ul><h3 id="observa-es-2"><strong>Observações</strong></h3><p>Às vezes, são feitas perguntas que envolvem representações binárias e operações <em>bitwise</em>. Você deve saber como converter um número de decimal para binário e vice-versa em sua linguagem de programação escolhida.</p><p>Alguns trechos úteis:</p><ul><li>O teste do k-ésimo bit está definido: num &amp; (1 &lt;&lt; k) != 0</li><li>Defina o k-ésimo bit: num |= (1 &lt; &lt;&lt; k)</li><li>Desligue o k-ésimo bit: num &amp;= ~(1 &lt;&lt;&lt; k)</li><li>Alterne o k-ésimo bit: num ^= (1 &lt; &lt;&lt; k)</li><li>Para verificar se um número é uma potência de 2: num &amp; num - 1 == 0.</li></ul><h3 id="casos-lim-trofes-1"><strong>Casos limítrofes</strong></h3><ul><li>Verificação de sobrefluxo/baixo fluxo</li><li>Números negativos</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--1"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/sum-of-two-integers/">Soma de dois inteiros</a></li><li><a href="https://leetcode.com/problems/number-of-1-bits/">Número de 1 Bits</a></li><li><a href="https://leetcode.com/problems/counting-bits/">Contagem de Bits</a></li><li><a href="https://leetcode.com/problems/missing-number/">Número em falta</a></li><li><a href="https://leetcode.com/problems/reverse-bits/">Bits Reversos</a></li></ul><h2 id="programa-o-din-mica"><strong>Programação dinâmica</strong></h2><h3 id="links-de-estudo-1"><strong>Links de estudo</strong></h3><ul><li><a href="https://www.freecodecamp.org/news/demystifying-dynamic-programming-3efafb8d4296">Desmistificando a programação dinâmica</a> (texto em inglês)</li></ul><h3 id="observa-es-3"><strong>Observações</strong></h3><p>A Programação Dinâmica (DP) é normalmente usada para resolver problemas de otimização. Alaina Kafkes escreveu um <a href="https://www.freecodecamp.org/news/demystifying-dynamic-programming-3efafb8d4296">artigo fantástico</a> sobre a solução de problemas de DP. Você deve lê-lo.</p><p>A única maneira de melhorar no DP é com a prática. É preciso muita prática para reconhecer que um problema pode ser resolvido pela PD.</p><p>Para otimizar o espaço, às vezes não é necessário armazenar a tabela de DP inteira na memória. Os dois últimos valores ou as duas últimas filas da matriz serão suficientes.</p><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--2"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="http://www.geeksforgeeks.org/knapsack-problem/">0/1 Mochila</a></li><li><a href="https://leetcode.com/problems/climbing-stairs/">Escada</a></li><li><a href="https://leetcode.com/problems/coin-change/">Mudança de moeda</a></li><li><a href="https://leetcode.com/problems/longest-increasing-subsequence/">O maior aumento subsequente</a></li><li><a href="https://github.com/yangshun/tech-interview-handbook/blob/master/algorithms">Subsequências mais longas comuns</a></li><li><a href="https://leetcode.com/problems/word-break/">Problema de quebra de palavras</a></li><li><a href="https://leetcode.com/problems/combination-sum-iv/">Soma combinada</a></li><li><a href="https://leetcode.com/problems/house-robber/">Assalto à casa</a> e <a href="https://leetcode.com/problems/house-robber-ii/">Assalto à casa II</a></li><li><a href="https://leetcode.com/problems/decode-ways/">Formas de decodificação</a></li><li><a href="https://leetcode.com/problems/unique-paths/">Caminhos únicos</a></li><li><a href="https://leetcode.com/problems/jump-game/">Jogo de pular</a></li></ul><h2 id="geometria"><strong>Geometria</strong></h2><h3 id="observa-es-4"><strong>Observações</strong></h3><p>Ao comparar a distância euclidiana entre dois pares de pontos, o uso de dx² + dy² é suficiente. É desnecessário estabelecer a raiz quadrada do valor.</p><p>Para descobrir se dois círculos se sobrepõem, verifique se a distância entre os dois centros dos círculos é menor do que a soma de seus raios.</p><h2 id="grafos"><strong>Grafos</strong></h2><h3 id="links-de-estudo-textos-em-ingl-s-"><strong>Links de estudo (textos em inglês)</strong></h3><ul><li><a href="https://medium.com/basecs/from-theory-to-practice-representing-graphs-cfd782c5be38">Da teoria à prática: representando grafos</a></li><li><a href="https://medium.com/basecs/deep-dive-through-a-graph-dfs-traversal-8177df5d0f13">Mergulhar fundo através de um grafo: travessia DFS</a></li><li><a href="https://medium.com/basecs/going-broad-in-a-graph-bfs-traversal-959bd1a09255">Tornando o grafo mais amplo: travessia BFS</a></li></ul><h3 id="observa-es-5">Observações</h3><p>Esteja familiarizado com as várias representações de grafos e algoritmos de pesquisa de grafos, bem como com suas complexidades de tempo e espaço.</p><p>Você pode receber uma lista de arestas e ser encarregado de construir seu próprio grafo a partir das arestas para realizar uma travessia. As representações de grafos comuns são:</p><ul><li>Matriz adjacente</li><li>Lista adjacente</li><li>HashMap dos HashMaps</li></ul><p>Algumas entradas parecem ser árvores, mas, na verdade, são grafos. Esclareça isto com seu entrevistador. Nesse caso, você terá que lidar com ciclos e manter um conjunto de nós visitados quando estiver percorrendo os grafos.</p><h3 id="algoritmos-de-busca-de-grafos"><strong>Algoritmos de busca de grafos</strong></h3><ul><li>Comum: busca primeiramente em largura (BFS), busca primeiramente em profundidade (DFS)</li><li>Incomum: ordenação topológica, o algoritmo de Dijkstra</li><li>Raro: algoritmo Bellman-Ford, algoritmo Floyd-Warshall, algoritmo Prim e algoritmo Kruskal</li></ul><p>Nas entrevistas de programação, os grafos são comumente representados como matrizes 2D, onde as células são os nós e cada célula pode percorrer até suas células adjacentes (para cima, para baixo, para a esquerda e para a direita). Portanto, é importante estar familiarizado com a travessia de uma matriz 2-D.</p><p>Ao atravessar recursivamente a matriz, certifique-se sempre de que sua próxima posição esteja dentro dos limites da matriz. Mais dicas para fazer a DFS em uma matriz podem ser encontradas <a href="https://discuss.leetcode.com/topic/66065/python-dfs-bests-85-tips-for-all-dfs-in-matrix-question/">aqui</a> (em inglês). Um modelo simples para fazer a DFS em uma matriz é algo parecido com isto:</p><pre><code class="language-py">def traverse(matrix):
  rows, cols = len(matrix), len(matrix[0])
  visited = set()
  directions = ((0, 1), (0, -1), (1, 0), (-1, 0))
  def dfs(i, j):
    if (i, j) in visited:
      return
    visited.add((i, j))
    # Traverse neighbors
    for direction in directions:
      next_i, next_j = i + direction[0], j + direction[1]
      if 0 &lt;= next_i &lt; rows and 0 &lt;= next_j &lt; cols: # Check boundary
        # Add any other checking here ^
        dfs(next_i, next_j)
  for i in range(rows):
    for j in range(cols):
      dfs(i, j)</code></pre><h3 id="casos-lim-trofes-2"><strong>Casos limítrofes</strong></h3><ul><li>Grafo vazio</li><li>Grafo com um ou dois nós</li><li>Grafos desconjuntados</li><li>Grafos com ciclos</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--3"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/clone-graph/">Clonar grafo</a></li><li><a href="https://leetcode.com/problems/course-schedule/">Cronograma do curso</a></li><li><a href="https://leetcode.com/problems/alien-dictionary/">Dicionário de alienígenas</a></li><li><a href="https://leetcode.com/problems/pacific-atlantic-water-flow/">Fluxo de água do Atlântico Pacífico</a></li><li><a href="https://leetcode.com/problems/number-of-islands/">Número de ilhas</a></li><li><a href="https://leetcode.com/problems/graph-valid-tree/">Árvore válida de grafo</a></li><li><a href="https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/">Número de componentes conectados em um grafo indireto</a></li><li><a href="https://leetcode.com/problems/longest-consecutive-sequence/">Sequência consecutiva mais longa</a></li></ul><h2 id="intervalo"><strong>Intervalo</strong></h2><h3 id="observa-es-6"><strong>Observações</strong></h3><p>Perguntas de intervalo são perguntas que dão uma série de arrays de dois elementos (um intervalo). Os dois valores representam um valor inicial e um valor final. As perguntas de intervalo são consideradas parte da família de arrays, mas envolvem algumas técnicas comuns. Portanto, elas têm sua própria seção especial.</p><p>Um exemplo de intervalo de arrays: <code>[[1, 2], [4, 7]]</code>.</p><p>As perguntas de intervalo podem ser complicadas para aqueles que não têm experiência com elas. Isto se deve ao grande número de casos a serem considerados quando os arrays de intervalo se sobrepõem.</p><p>Esclareça com o entrevistador se <code>[1, 2]</code> e <code>[2, 3]</code> são considerados intervalos sobrepostos, pois isso afeta a forma como você vai escrever suas verificações de igualdade.</p><p>Uma rotina comum para perguntas de intervalo é ordenar o conjunto de intervalos pelo valor inicial de cada intervalo.</p><p>Esteja familiarizado com escrever código para verificar se dois intervalos se sobrepõem e para unir dois intervalos sobrepostos:</p><pre><code class="language-js">def is_overlap(a, b):
  return a[0] &lt; b[1] and b[0] &lt; a[1]
  
def merge_overlapping_intervals(a, b):
  return [min(a[0], b[0]), max(a[1], b[1])]</code></pre><h3 id="casos-lim-trofes-3"><strong>Casos limítrofes</strong></h3><ul><li>Intervalo único</li><li>Intervalos não sobrepostos</li><li>Um intervalo totalmente consumido dentro de outro intervalo</li><li>Intervalos em duplicata</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--4"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/insert-interval/">Intervalo de inserção</a></li><li><a href="https://leetcode.com/problems/merge-intervals/">Intervalos de <em>merging</em></a></li><li><a href="https://leetcode.com/problems/meeting-rooms/">Salas de reunião</a> e <a href="https://leetcode.com/problems/meeting-rooms-ii/">Salas de reunião II</a></li><li><a href="https://leetcode.com/problems/non-overlapping-intervals/">Intervalos não sobrepostos</a></li></ul><h2 id="lista-vinculada"><strong>Lista vinculada</strong></h2><h3 id="observa-es-7"><strong>Observações</strong></h3><p>Como os arrays, listas vinculadas são usadas para representar dados sequenciais. O benefício das listas vinculadas é que a inserção e exclusão de código de qualquer parte da lista é O(1), enquanto, nos arrays, os elementos têm que ser mudados.</p><p>Adicionar um nó fictício na cabeça e/ou na cauda pode ajudar a lidar com muitos casos limítrofes onde as operações têm que ser realizadas na cabeça ou na cauda. A presença de nós fictícios garante que as operações nunca terão sido executadas na cabeça ou na cauda. Os nós fictícios removem a dor de cabeça de escrever verificações condicionais para lidar com indicações nulas. Certifique-se de removê-los ao final da operação.</p><p>Às vezes, os problemas de listas vinculadas podem ser resolvidos sem armazenamento adicional. Tente pegar ideias emprestadas para reverter um problema de lista vinculada.</p><p>Para exclusão em listas vinculadas, você pode modificar os valores dos nós ou alterar os ponteiros dos nós. Você pode precisar manter uma referência ao elemento anterior.</p><p>Para particionar as listas vinculadas, crie duas listas vinculadas separadas e junte-as novamente.</p><p>Os problemas de listas vinculadas compartilham semelhanças com problemas de array. Pense em como você resolveria um problema de array e o aplicaria a uma lista vinculada.</p><p>Duas abordagens de ponteiro também são comuns para listas vinculadas:</p><ul><li>Obtendo o k-ésimo nó a partir do último nó: use dois ponteiros, onde um está k nós à frente do outro. Quando o nó à frente chega ao fim, o outro nó está k nós atrás.</li><li>Detectando ciclos: use dois ponteiros, onde um ponteiro aumenta duas vezes mais do que o outro. Se os dois ponteiros se encontrarem, significa que há um ciclo.</li><li>Obtendo o nó do meio: use dois ponteiros. Um ponteiro incrementa duas vezes mais que o outro. Quando o nó mais rápido chegar ao final da lista, o mais lento estará no meio.</li></ul><p>Esteja familiarizado com as seguintes rotinas, pois muitas perguntas da lista vinculada fazem uso de uma ou mais destas rotinas em sua solução.</p><ul><li>Contar o número de nós na lista vinculada</li><li>Reverter uma lista vinculada no local</li><li>Encontre o nó central da lista vinculada usando ponteiros rápidos ou lentos</li><li>Fazer a fusão (do inglês, <em>merge</em>) de duas listas juntas</li></ul><h3 id="casos-lim-trofes-4"><strong>Casos limítrofes</strong></h3><ul><li>Nó único</li><li>Dois nós</li><li>A lista vinculada tem um ciclo. Esclareça com o entrevistador se pode haver um ciclo na lista. Normalmente, a resposta é não.</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--5"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/reverse-linked-list/">Reverter uma lista vinculada</a></li><li><a href="https://leetcode.com/problems/linked-list-cycle/">Detectar ciclo em uma lista vinculada</a></li><li><a href="https://leetcode.com/problems/merge-two-sorted-lists/">Fusão de duas listas ordenadas</a></li><li><a href="https://leetcode.com/problems/merge-k-sorted-lists/">Fusão de listas K ordenadas</a></li><li><a href="https://leetcode.com/problems/remove-nth-node-from-end-of-list/">Remover o nó do fim da lista</a></li><li><a href="https://leetcode.com/problems/reorder-list/">Reordenar a lista</a></li></ul><h2 id="matem-tica"><strong>Matemática</strong></h2><h4 id="observa-es-8"><strong>Observações</strong></h4><p>Se o código envolver divisão ou módulo, lembre-se de verificar a divisão ou o módulo em função do caso com 0 (zero).</p><p>Quando uma pergunta envolve "um múltiplo de um número", o módulo pode ser útil.</p><p>Verifique e administre overflow e underflow se estiver usando uma linguagem tipada como Java e C++. No mínimo, mencione que o <em>overflow </em>ou que o <em>underflow </em>é possível e pergunte se você precisa lidar com ele.</p><p>Considere números negativos e números de ponto flutuante. Isso pode parecer óbvio, mas quando você está sob pressão em uma entrevista, muitos pontos óbvios passam despercebidos.</p><p>Se a pergunta for para implementar um operador como potência, raiz quadrada ou divisão, e se for para ser mais rápido que O(n), a busca binária é geralmente a abordagem.</p><h3 id="algumas-f-rmulas-comuns"><strong>Algumas fórmulas comuns</strong></h3><ul><li>Soma de 1 para N = (n+1) * n/2</li><li>Soma de progressões geométricas = 2⁰ + 2¹ + 2² + 2³ + … 2^n = 2^(n+1)-1</li><li>Permutações de N = N! / (N-K)!</li><li>Combinações de N = N! / (K! * (N-K)!)</li></ul><h3 id="casos-lim-trofes-5"><strong>Casos limítrofes</strong></h3><ul><li>Divisão por 0</li><li><em>Overflow </em>e <em>underflow</em> de números inteiros</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--6"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/powx-n/">Potência</a><a href="https://leetcode.com/problems/powx-n/" rel="noopener">(x, n)</a></li><li><a href="https://leetcode.com/problems/sqrtx/">Raiz quadrada(x)</a></li><li><a href="https://leetcode.com/problems/integer-to-english-words/">Inteiro para palavras em inglês</a></li></ul><h2 id="matriz"><strong>Matriz</strong></h2><h3 id="notas"><strong>Notas</strong></h3><p>Uma matriz é um array bidimensional. As questões envolvendo matrizes estão geralmente relacionadas à programação dinâmica ou à travessia do grafo.</p><p>Para perguntas que envolvam travessia ou programação dinâmica, faça uma cópia da matriz com as mesmas dimensões e inicializada com valores vazios. Utilize esses valores para armazenar o estado visitado ou a tabela de programação dinâmica. Esteja familiarizado com esta rotina:</p><pre><code class="language-py">rows, cols = len(matrix), len(matrix[0])
copy = [[0 for _ in range(cols)] for _ in range(rows)</code></pre><ul><li>Muitos jogos baseados em grade podem ser modelados como uma matriz, como, por exemplo, o Jogo da Velha, Sudoku, palavras cruzadas, Ligue 4 e Batalha Naval. Não é raro ser solicitada a verificação da condição de vencedor do jogo. Para jogos como o Jogo da Velha, o Ligue 4 e as Palavras Cruzadas, a verificação tem que ser feita vertical e horizontalmente. Um truque é escrever o código para verificar a matriz para as células horizontais. Em seguida, transpor a matriz, reutilizando a lógica usada para verificação horizontal para verificar as células originalmente verticais (que agora são horizontais).</li><li>A transposição de uma matriz em Python é simples:</li></ul><pre><code class="language-py">transposed_matrix = zip(*matrix)</code></pre><h3 id="casos-lim-trofes-6"><strong>Casos limítrofes</strong></h3><ul><li>Matriz vazia. Verifique se nenhuma das matrizes tem comprimento 0.</li><li>Matriz 1 x 1.</li><li>Matriz com apenas uma linha ou coluna.</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--7"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/set-matrix-zeroes/">Definir a matriz zero</a> </li><li><a href="https://leetcode.com/problems/spiral-matrix/">Matriz espiral</a></li><li><a href="https://leetcode.com/problems/rotate-image/">Rotacionar imagem</a></li><li><a href="https://leetcode.com/problems/word-search/">Caça-palavras</a></li></ul><h2 id="recurs-o"><strong>Recursão</strong></h2><h3 id="observa-es-9"><strong>Observações</strong></h3><p>A recursividade é útil para a permutação, pois gera todas as combinações e perguntas baseadas em árvores. Você deve saber como gerar todas as permutações de uma sequência, bem como lidar com as duplicatas.</p><p>Lembre-se sempre de definir um caso base para que sua recorrência termine.</p><p>A recorrência utiliza implicitamente uma pilha. Assim, todas as abordagens recursivas podem ser reescritas iterativamente usando uma pilha.</p><p>Cuidado com os casos em que o nível de recorrência vai muito fundo e causa um transbordamento de pilha (o limite padrão em Python é 1000). Você pode receber pontos de bônus por apontar isso para o entrevistador.</p><p>A recursividade nunca terá complexidade espacial O(1) porque uma pilha está envolvida, a menos que haja uma <a href="https://stackoverflow.com/questions/310974/what-is-tail-call-optimization">otimização da chamada de cauda</a> (TCO). Descubra se a linguagem escolhida dá suporte à TCO.</p><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--8"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/subsets/">Subconjuntos</a> e <a href="https://leetcode.com/problems/subsets-ii/">Subconjuntos II</a></li><li><a href="https://leetcode.com/problems/strobogrammatic-number-ii/">Número II </a><a href="https://leetcode.com/problems/strobogrammatic-number-ii/" rel="noopener">Strobogrammatic</a></li></ul><h2 id="string"><strong>String</strong></h2><h3 id="observa-es-10"><strong>Observações</strong></h3><p>Leia as dicas acima sobre <a href="https://www.techinterviewhandbook.org/">sequências</a>. Elas também se aplicam às strings.</p><p>Pergunte sobre o conjunto de caracteres de entrada e a distinção entre maiúsculas e minúsculas. Normalmente, os caracteres são limitados a caracteres latinos em letras minúsculas – por exemplo, de a até z.</p><p>Quando você precisa comparar strings onde a ordem não é importante (como o anagrama), você pode considerar o uso de um HashMap como um contador. Se sua linguagem tiver uma classe de contador embutida como no Python, peça para usar isso em seu lugar.</p><p>Se você precisa manter um contador de caracteres, um erro comum é dizer que a complexidade de espaço necessária para o contador é O(n). O espaço necessário para um contador é O(1) e não O(n). Isto porque o limite superior é o intervalo de caracteres, que, normalmente, é uma constante fixa de 26. O conjunto de entrada é apenas de caracteres latinos em letras minúsculas.</p><p>As estruturas de dados comuns para a busca eficiente de strings são:</p><ul><li><a href="https://www.wikiwand.com/en/Trie">Árvore de Trie/Prefixos</a></li><li><a href="https://www.wikiwand.com/en/Suffix_tree">Árvore de Sufixos</a></li></ul><p>Algoritmos de strings comuns são:</p><ul><li><a href="https://www.wikiwand.com/en/Rabin%E2%80%93Karp_algorithm" rel="noopener">Rabin Karp</a>, que realiza buscas eficientes de substrings, utilizando um hash "rolante"</li><li><a href="https://www.wikiwand.com/en/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm" rel="noopener">KMP</a>, que realiza buscas eficientes de substrings</li></ul><h3 id="caracteres-n-o-repetentes"><strong>Caracteres não repetentes</strong></h3><p>Use uma máscara de 26 bits para indicar quais caracteres latinos em letras minúsculas estão dentro da string.</p><pre><code class="language-py">mask = 0
for c in set(word):
  mask |= (1 &lt;&lt; (ord(c) - ord('a')))</code></pre><p>Para determinar se duas strings têm caracteres em comum, execute &amp; nas duas máscaras de bits. Se o resultado não for zero, <code>mascara_a &amp; mascara_b &gt; 0</code> , então as duas strings têm caracteres em comum.</p><h3 id="anagrama"><strong>Anagrama</strong></h3><p>Um anagrama é um trocador de palavras ou jogo de palavras. É o resultado de reorganizar as letras de uma palavra ou frase para produzir uma nova palavra ou frase, enquanto usa todas as letras originais apenas uma vez. Em entrevistas, normalmente só nos preocupamos com palavras sem espaços nelas.</p><p>Para determinar se duas strings são anagramas, existem algumas abordagens plausíveis:</p><ul><li>A ordenação de ambas as strings deve produzir a mesma string resultante. Isso leva tempo O(nlgn) e espaço O(lgn).</li><li>Se mapearmos cada caractere para um número primo e multiplicarmos cada número mapeado juntos, os anagramas devem ter o mesmo múltiplo (decomposição do fator primo). Isto leva tempo O(n) e espaço O(1).</li><li>A contagem da frequência dos caracteres ajudará a determinar se duas strings são anagramas. Isso também leva tempo O(n) e espaço O(1)</li></ul><h3 id="pal-ndromo"><strong>Palíndromo</strong></h3><p>Um <strong>palíndromo</strong> é uma palavra, frase, <a href="https://en.wikipedia.org/wiki/Palindromic_number">número</a> ou outra sequência de <a href="https://en.wikipedia.org/wiki/Character_(symbol)">caracteres</a> que é lido do mesmo modo para trás e para frente, tais como "<em>madam"</em> ou "<em>racecar</em>".</p><p>Aqui estão maneiras de determinar se uma string é um palíndromo:</p><ul><li>Reverta a string e ela deve ser igual a si mesma.</li><li>Ter dois ponteiros no início e no final da string. Mova os ponteiros para dentro até que eles se encontrem. Em qualquer momento, os caracteres em ambos os ponteiros devem coincidir.</li></ul><p>A ordem dos caracteres dentro da string importa, portanto, os HashMaps geralmente não são úteis.</p><p>Quando se trata de contar o número de palíndromos, um truque comum é ter dois ponteiros que se movem para fora e para longe do meio. Note que os palíndromos podem ter um comprimento par ou ímpar. Para cada posição de pivô central, é necessário verificá-la duas vezes: uma vez que inclua o caractere e outra sem o caractere.</p><ul><li>Para as substrings, você pode terminar antecipadamente uma vez que não haja correspondência.</li><li>Para as subsequentes, use programação dinâmica, pois existem subproblemas sobrepostos. Confira <a href="https://leetcode.com/problems/longest-palindromic-subsequence/">esta pergunta</a> (em inglês, no LeetCode).</li></ul><h3 id="casos-lim-trofes-7"><strong>Casos limítrofes</strong></h3><ul><li>String vazia</li><li>String de um único caractere</li><li>Strings com apenas um caractere distinto</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--9"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/longest-substring-without-repeating-characters/">A substring mais longa sem repetição de caracteres</a></li><li><a href="https://leetcode.com/problems/longest-repeating-character-replacement/">Substituição mais longa de caracteres repetitivos</a></li><li><a href="https://leetcode.com/problems/minimum-window-substring/description/">Substring mínimaqde janela</a></li><li><a href="https://leetcode.com/problems/encode-and-decode-strings/">Codificação e decodificação de strings</a></li><li><a href="https://leetcode.com/problems/valid-anagram">Anagrama válido</a></li><li><a href="https://leetcode.com/problems/group-anagrams/">Anagramas de grupo</a></li><li><a href="https://leetcode.com/problems/valid-parentheses">Parênteses válidos</a></li><li><a href="https://leetcode.com/problems/valid-palindrome/">Palíndromo válido</a></li><li><a href="https://leetcode.com/problems/longest-palindromic-substring/">Substring palindrômica mais longa</a></li><li><a href="https://leetcode.com/problems/palindromic-substrings/">Substrings palindrômicas</a></li></ul><h3 id="-rvore"><strong>Árvore</strong></h3><h3 id="links-de-estudo-em-ingl-s-"><strong>Links de estudo (em inglês)</strong></h3><h4></h4><ul><li><a href="https://medium.com/basecs/leaf-it-up-to-binary-trees-11001aaf746d">Folheie até as árvores binárias</a></li></ul><h3 id="observa-es-11"><strong>Observações</strong></h3><p>Uma árvore é um grafo acíclico, não direcionado e conectado.</p><p>A recursividade é uma abordagem comum para as árvores. Quando você perceber que o problema da subárvore pode ser usado para resolver o problema inteiro, tente usar a recursividade.</p><p>Ao utilizar a recorrência, lembre-se sempre de verificar o caso base, geralmente onde o nó é nulo.</p><p>Quando você for solicitado a atravessar uma árvore por nível, use a busca em profundidade.</p><p>Às vezes, é possível que sua função recursiva precise retornar dois valores.</p><p>Se a questão envolver a soma dos nós ao longo do caminho, certifique-se de verificar se os nós podem ser negativos.</p><p>Você deve estar muito familiarizado com a escrita de travessias de pré-ordem, dentro da ordem e pós-ordem recursivamente. Como extensão, desafie-se escrevendo-as iterativamente. Às vezes, os entrevistadores pedem aos candidatos a abordagem iterativa, especialmente se o candidato terminar de escrever a abordagem recursiva muito rapidamente.</p><h3 id="-rvore-bin-ria"><strong>Árvore binária</strong></h3><p>A travessia em ordem de uma árvore binária é insuficiente para serializar uma árvore de maneira única. Também é necessária a travessia pré-ordem ou pós-ordem.</p><h2 id="-rvore-de-busca-bin-ria-binary-search-tree-bst-">Árvore de busca binária - Binary search tree (BST)</h2><p>A travessia em ordem de uma BST dará a você todos os elementos em ordem.</p><p>Esteja muito familiarizado com as propriedades de uma BST. Valide se uma árvore binária é uma BST. Isso aparece com mais frequência do que o esperado.</p><p>Quando uma pergunta envolve uma BST, o entrevistador geralmente está procurando uma solução que funcione mais rápido que a O(n).</p><h3 id="casos-lim-trofes-8"><strong>Casos limítrofes</strong></h3><ul><li>Árvore vazia</li><li>Nó único</li><li>Dois nós</li><li>Árvore muito desbalanceada (como uma lista vinculada)</li></ul><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--10"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/maximum-depth-of-binary-tree/">Profundidade máxima da árvore binária</a></li><li><a href="https://leetcode.com/problems/same-tree/">A mesma árvore</a></li><li><a href="https://leetcode.com/problems/invert-binary-tree/">Árvore binária invertida ou virada</a></li><li><a href="https://leetcode.com/problems/binary-tree-maximum-path-sum/">Soma máxima do caminho da árvore binária</a></li><li><a href="https://leetcode.com/problems/binary-tree-level-order-traversal/">Travessia de ordem de nível de árvore binária</a></li><li><a href="https://leetcode.com/problems/serialize-and-deserialize-binary-tree/">Serializar e desserializar a árvore binária</a></li><li><a href="https://leetcode.com/problems/subtree-of-another-tree/">Subárvore de outra árvore</a></li><li><a href="https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/">Construir a árvore binária a partir da travessia de pré-ordem e em ordem</a></li><li><a href="https://leetcode.com/problems/validate-binary-search-tree/">Validar árvore de busca binária</a></li><li><a href="https://leetcode.com/problems/kth-smallest-element-in-a-bst/">K-ésimo menor elemento de uma BST</a></li><li><a href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/">O menor ancestral comum da BST</a></li></ul><h2 id="tries"><strong>Tries</strong></h2><h3 id="links-de-estudo-em-ingl-s--1"><strong>Links de estudo (em inglês)</strong></h3><ul><li><a href="https://medium.com/basecs/trying-to-understand-tries-3ec6bede0014">Tentando entender as tries</a></li><li><a href="https://leetcode.com/articles/implement-trie-prefix-tree/">Implemente a Trie (Árvore de prefixos)</a></li></ul><h3 id="observa-es-12"><strong>Observações</strong></h3><p>Tries são árvores especiais (árvores de prefixos) que tornam mais eficiente a busca e o armazenamento de strings. As <em>tries</em> têm muitas aplicações práticas, tais como a realização de buscas e o fornecimento de autocompletar. É útil conhecer essas aplicações comuns para que você possa identificar facilmente quando um problema pode ser resolvido de modo eficiente usando uma <em>trie</em>.</p><p>Às vezes, o pré-processamento de um dicionário de palavras (dado em uma lista) em uma <em>trie</em> melhorará a eficiência da busca por uma palavra de comprimento k, entre n palavras. A busca torna-se O(k) em vez de O(n).</p><p>Esteja familiarizado com a implementação, a partir do zero, de uma classe <code>Trie</code> e seus métodos <code>add</code>, <code>remove</code> e <code>search</code>.</p><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--11"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/implement-trie-prefix-tree">Implemente Trie (Prefixo Árvore)</a></li><li><a href="https://leetcode.com/problems/add-and-search-word-data-structure-design">Adicionar e pesquisar palavra</a></li><li><a href="https://leetcode.com/problems/word-search-ii/">Caça-palavras II</a></li></ul><h2 id="heap"><strong>Heap</strong></h2><h3 id="links-de-estudo-em-ingl-s--2"><strong>Links de estudo (em inglês)</strong></h3><ul><li><a href="https://medium.com/basecs/learning-to-love-heaps-cef2b273a238">Aprendendo a amar os Heaps</a></li></ul><h3 id="observa-es-13"><strong>Observações</strong></h3><p>Se você vir um k superior ou inferior mencionado na pergunta, geralmente, é um sinal de que uma <em>heap</em> pode ser usada para resolver o problema, como em <a href="https://leetcode.com/problems/top-k-frequent-elements/">K elementos mais frequentes</a>.</p><p>Se você precisar dos k elementos superiores, use uma <em>heap </em>de tamanho k. Faça a iteração através de cada elemento, inserindo-o na <em>heap</em>. Sempre que o tamanho da <em>heap </em>exceder k, remova o elemento menor. Isso garantirá que você tenha os k elementos maiores.</p><h3 id="perguntas-pr-ticas-exemplos-em-ingl-s-do-leetcode--12"><strong>Perguntas práticas (exemplos em inglês do LeetCode)</strong></h3><ul><li><a href="https://leetcode.com/problems/merge-k-sorted-lists/">Fusão de listas K ordenadas</a></li><li><a href="https://leetcode.com/problems/top-k-frequent-elements/">K elementos mais frequentes</a></li><li><a href="https://leetcode.com/problems/find-median-from-data-stream/">Encontre a mediana do fluxo de dados</a></li></ul><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>As entrevistas de programação são difíceis. Felizmente, no entanto, você pode melhorar para elas, estudando e praticando para elas e fazendo entrevistas simuladas.</p><p>Recapitulando: para se sair bem nas entrevistas de programação:</p><ol><li>Decida sobre uma linguagem de programação</li><li>Estude fundamentos da Ciência da Computação</li><li>Pratique a solução de questões de algoritmos</li><li>Internalize <a href="https://github.com/yangshun/tech-interview-handbook/blob/master/preparing/cheatsheet.md"></a><a href="https://www.techinterviewhandbook.org/">o que se faz e o que não se faz nas entrevistas</a></li><li>Pratique através de entrevistas técnicas simuladas</li><li>Faça a entrevista com sucesso e consiga o emprego</li></ol><p>Seguindo essas etapas, você melhorará suas habilidades em entrevistas de programação e estará um passo mais próximo (ou provavelmente mais) de conseguir o emprego dos seus sonhos.</p><p>Sucesso para você!</p><p>O conteúdo deste artigo também <a href="https://www.techinterviewhandbook.org/">pode ser encontrado aqui</a>. Atualizações futuras serão publicadas lá. Pedidos de sugestões e correções são bem-vindos.</p><p>Se você gostou deste artigo, compartilhe-o com seus amigos!</p><p>Você pode seguir o autor no <a href="https://github.com/yangshun" rel="noopener">GitHub</a> e no <a href="https://twitter.com/yangshunz" rel="noopener">Twitter</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de funções da AWS Lambda para Cron Jobs – como agendar tarefas ]]>
                </title>
                <description>
                    <![CDATA[ Os Cron Jobs são normalmente usados para agendar comandos em um horário específico. Você pode usá-los para tarefas como executar backups, monitorar o status do sistema ou executar tarefas de manutenção do sistema. Os Cron Jobs são utilitários úteis para os administradores de sistemas. Quando você está administrando um sistema ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/tutorial-de-funcoes-da-aws-lambda-para-cron-jobs-como-agendar-tarefas-como-agendar-tarefas/</link>
                <guid isPermaLink="false">635fc2df7e77d305f28d8462</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Thu, 22 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/aws-lambda---deno.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/using-lambda-functions-as-cronjobs/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Cron Job AWS Lambda Functions Tutorial – How to Schedule Tasks</a>
      </p><p>Os Cron Jobs são normalmente usados para agendar comandos em um horário específico. Você pode usá-los para tarefas como executar backups, monitorar o status do sistema ou executar tarefas de manutenção do sistema.</p><p>Os Cron Jobs são utilitários úteis para os administradores de sistemas. Quando você está administrando um sistema na nuvem, os Cron Jobs ainda são muito úteis – afinal, você ainda precisa fazer muitas tarefas administrativas nos sistemas.</p><p>Uma maneira de executar Cron Jobs na nuvem é usar uma função como um serviço (FaaS), como a Lambda no ecossistema AWS.</p><p>As funções executam quando são acionadas para isso e executam o código na nuvem sem a necessidade de prover ou manter qualquer infraestrutura. Elas também podem ser configuradas para serem executadas em um determinado momento ou com certa periodicidade, como os Cron Jobs tradicionais.</p><p>Neste artigo, usarei o ecossistema AWS para mostrar um exemplo concreto de como criar um Cron Job usando uma função na nuvem.</p><h2 id="eventos-da-amazon-cloudwatch"><strong>Eventos da Amazon CloudWatch </strong></h2><p>A fim de usar a função Lambda como um Cron Job, precisamos entender os eventos da Amazon CloudWatch.</p><p>Os eventos da Amazon CloudWatch são enviados quando há mudanças nos recursos da AWS. Esses eventos podem acionar uma função AWS Lambda. Quando os seus recursos da AWS mudam de estado, eles automaticamente enviam eventos CloudWatch para o stream de eventos.</p><p>Portanto, você pode criar uma regra que aciona uma função Lambda específica quando algo acontece. Por exemplo, você pode invocar automaticamente uma função Lambda quando há uma mudança em um grupo AutoScaling.</p><p>Além disso, os eventos CloudWatch podem invocar uma função Lambda para ser executada regularmente. Deste modo, você pode ter, por exemplo, uma função Lambda que desativa todos os seus testes e desenvolvimento em EC2 depois das 18h e outra que os ativa após as 8h.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/diagram2.png" class="kg-image" alt="diagram2" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/diagram2.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/diagram2.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/diagram2.png 1338w" sizes="(min-width: 720px) 720px" width="1338" height="382" loading="lazy"><figcaption>Quando há uma mudança em um grupo AutoScaling, o evento de CloudWatch gerado aciona uma função Lambda</figcaption></figure><h2 id="configurando-a-demonstra-o"><strong>Configurando a demonstração</strong></h2><p>Quero mostrar a você um exemplo de uma função Lambda que pode realizar ações em suas instâncias da EC2. Vou usar o <a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html">AWS SAM</a> para definir a minha função Lambda como infraestrutura como código.</p><p>Se você quiser experimentar essa demonstração, precisará ter uma conta na AWS e uma ou mais instâncias da EC2 configuradas em sua conta da AWS. Estas são as que vamos manipular a partir das funções Lambda. As instâncias da EC2 são a versão da AWS das máquinas virtuais na nuvem.</p><p>Você pode tentar a demonstração no <a href="https://aws.amazon.com/cloud9/">IDE AWS Cloud9</a> (um IDE baseado em navegador), já que o AWS SAM já está configurado nesse IDE. Se você quiser saber como usar a IDE AWS Cloud9 para operar as funções Lambda, você pode conferir este <a href="https://youtu.be/JmEMBxfYtf4">vídeo</a> (em inglês).</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/JmEMBxfYtf4?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="PAIR PROGRAMMING IN REAL TIME WITH LAMBDA FUNCTIONS using AWS Cloud9 and more" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p>Neste exemplo, vamos começar e parar as instâncias da EC2 usando duas funções Lambda da AWS diferentes, que são acionadas em um determinado momento. Vamos iniciar as instâncias às 8h todos os dias e desativá-las às 18h, quando o dia terminar.</p><p>Para isso, vamos usar um evento CloudWatch para acionar a função Lambda no momento certo, além do AWS SDK para realizar as operações nas instâncias.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/digram1-1.png" class="kg-image" alt="digram1-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/digram1-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/digram1-1.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/digram1-1.png 1200w" sizes="(min-width: 720px) 720px" width="1200" height="384" loading="lazy"><figcaption>Em um momento específico, é acionada uma função Lambda que operará em um conjunto de instâncias da EC2</figcaption></figure><p>O código finalizado para o exemplo está disponível neste repositório do <a href="https://github.com/mavi888/lambda-cronjobs">GitHub</a>. Para que esse código funcione no IDE AWS Cloud9, você precisa<a href="https://help.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account"> </a><a href="https://help.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account"></a><a href="https://help.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account">configurar</a> a<a href="https://help.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account"> sua </a>conta do GitHub no IDE para poder clonar o projeto e depois cloná-lo dentro do IDE.</p><p>Quando tiver isso pronto, basta executar este comando dentro do diretório clonado:</p><pre><code>$ sam deploy --guided</code></pre><p>Ao executar esse comando, você receberá um conjunto de perguntas que precisa responder para configurar o projeto para que ele seja executado com sucesso.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/video1-1.gif" class="kg-image" alt="video1-1" width="600" height="544" loading="lazy"><figcaption>Como fazer o deploy do projeto na nuvem usando a CLI do AWS SAM</figcaption></figure><p>A primeira coisa que você precisa definir é um <strong>nome</strong> para o seu projeto. Em seguida, você definirá a <strong>região</strong> onde ele está sendo implantado – escolha a mesma região onde estão suas instâncias da EC2. Depois, precisamos dar ao roteiro de deploy uma <strong>lista das instâncias</strong> que queremos manipular. Estamos prontos – o deploy do projeto será feito em nossa conta da AWS.</p><h2 id="definindo-a-fun-o-aws-lambda"><strong>Definindo a função AWS Lambda</strong></h2><p>A primeira coisa que quero mostrar a você é como definimos uma função AWS Lambda, que é acionada em um tempo específico usando o AWS SAM. Esta definição estará no arquivo chamado "template.yml".</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/lambda-iac-start.png" class="kg-image" alt="lambda-iac-start" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/lambda-iac-start.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/lambda-iac-start.png 700w" width="700" height="654" loading="lazy"><figcaption>AWS SAM da função StartInstance</figcaption></figure><p>Essa é a aparência de uma função. Vejamos as linhas importantes:</p><p>A primeira linha é o nome da função – nesse caso, "<strong>StartInstanceFunction</strong>"<strong>.</strong></p><p>Depois, temos a definição de "<strong>Properties</strong>". A primeira propriedade é o "<strong>Handler</strong>". Aqui, especificaremos o módulo (arquivo) onde está o código que precisa ser executado e, depois, o método dentro desse módulo. </p><p>Então, temos "<strong>CodeUri</strong>", que é o caminho que mostra onde encontrar esse arquivo. Nesse caso, nosso código estará dentro de um diretório chamado "cron" em um arquivo chamado "handler.js" e em um método chamado "startInstance".</p><p>Depois disso, temos a definição de "<strong>Runtime</strong>". Usarei o NodeJS versão 12, mas você pode usar Python, Java, Go, C# ou qualquer outra linguagem de sua preferência. <a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html">A Lambda suporta múltiplos tempos de execução desde o princípio</a> e <a href="https://youtu.be/MS5pzddwwqU">você pode usar seu próprio ambiente de tempo de execução</a>, se quiser (links em inglês).</p><p>Temos a definição de "<strong>Environment</strong>", que usaremos para definir a única variável de ambiente. Essa variável nos permitirá enviar o código dinamicamente para diferentes instâncias de ids, dependendo da configuração de quando fazemos o deploy.</p><p>Depois disso, temos uma seção chamada "<strong>Policies</strong>", que é onde definimos as permissões que essa função Lambda específica terá.</p><p>É importante saber que todas as funções Lambda são criadas sem nenhuma permissão. Isso significa que elas não podem fazer nada em nenhum outro recurso da AWS.</p><p>Para que essa função Lambda possa iniciar uma instância da EC2, ela precisa de permissões para fazer essa ação específica sobre esse recurso específico da AWS. Nessa política específica, estamos concedendo permissões para iniciar TODAS as instâncias da EC2 nessa conta da AWS. TODAS são representadas com o "*" na seção de recursos.</p><p>Se você tiver esse código em produção, recomendo que você limite os recursos exatamente àqueles que você deseja que essa função Lambda possa iniciar.</p><p>Finalmente, a última seção é a seção "<strong>Events</strong>". Aqui, definiremos como essa função Lambda será acionada. Essa função será acionada com um evento CloudWatch agendado, que acionará a Lambda todos os dias às 8 da manhã. Basicamente, às 8 todos os dias, ela ativará todas as instâncias da EC2 que você especificar.</p><p>Há muitas regras para formar essa expressão Cron: por exemplo, para dizer que você gostaria que ela funcionasse apenas de segunda a sexta-feira (em inglês, <em>MONday-FRIday</em>), escreva <code>cron(0 8 ? * MON-FRI *)</code>. Você pode encontrar mais informações no site da documentação dos eventos CloudWatch <a href="https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html">aqui</a>. </p><h2 id="programando-a-fun-o-aws-lambda"><strong>Programando a função AWS Lambda</strong></h2><p>Agora que definimos a função Lambda, precisamos fornecer algum código para ela. Na pasta "cron", no arquivo "handler.js", precisamos adicionar o método chamado "<strong>startInstance</strong>", que tem esta aparência:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/lambda-code-start.png" class="kg-image" alt="lambda-code-start" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/lambda-code-start.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/lambda-code-start.png 838w" sizes="(min-width: 720px) 720px" width="838" height="948" loading="lazy"><figcaption>Código da função startInstance</figcaption></figure><p>Este método será chamado quando a função for acionada todos os dias às 8 horas da manhã. Ele obterá a lista de instâncias da EC2 a partir de uma variável de ambiente em que passamos todas as ids de instâncias durante o tempo de deploy. Em seguida, ele criará um array com essas instâncias.</p><p>Quando tiver esse array, ele chamará o AWS SDK e enviará o array de ids de instâncias como um parâmetro. Se houver algum erro, ele o registrará e o completará. Imediatamente após essa Lambda terminar a execução, você pode ir até o seu console da EC2 e ver que suas instâncias foram ativadas.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/start-instances.gif" class="kg-image" alt="start-instances" width="600" height="274" loading="lazy"><figcaption>As instâncias da EC2 iniciam automaticamente quando a função Lambda é executada</figcaption></figure><p>A função de desativar as instâncias da EC2 é muito semelhante, com algumas pequenas diferenças. Você pode encontrar o código para essa função neste <a href="https://github.com/mavi888/lambda-cronjobs">link</a> e verificá-lo.</p><h2 id="executando-o-cron-job"><strong>Executando o Cron Job</strong></h2><p>Para executar esse Cron Job, não há muito o que fazer. Depois de feito o deploy das duas funções em sua conta da AWS, na mesma região em que as suas instâncias estão, elas executarão e farão o que foram programadas para fazer.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/lambda-console-1.png" class="kg-image" alt="lambda-console-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/lambda-console-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/lambda-console-1.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/lambda-console-1.png 1404w" sizes="(min-width: 720px) 720px" width="1404" height="636" loading="lazy"><figcaption>A AWS Lambda funciona para iniciar e parar instâncias implantadas na minha conta da AWS</figcaption></figure><p>Agora, é preciso esperar até as 8h ou 18h para ver se elas funcionam. Se você quiser testar agora mesmo, mude o horário do evento na definição Lambda para um horário que sirva para você. Certifique-se de que a instância esteja ligada se você estiver planejando desligá-las ou o contrário, para que você possa ver as mudanças.</p><p>Espere e veja o que acontece no console da EC2. Logo após a configuração, você verá a instância ser ativada ou desativada na hora que você configurar. Isto continuará para sempre até que você remova as funções Lambda.</p><h2 id="limpeza-da-sua-conta-aws"><strong>Limpeza da sua conta AWS</strong></h2><p>Após completar essa demonstração, recomendo que você desligue (ou remova a instância que criou para testar) e remova as funções Lambda que você acabou de criar.</p><p>A remoção das funções Lambda é tão fácil quanto colocá-las no seu serviço CloudFormation. Em seu console de gerenciamento da AWS, remova a pilha de recursos que o AWS SAM criou.</p><p>Não se esqueça de encerrar e remover as instâncias da EC2 se você as criou apenas para essa demonstração.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/delete-lambda.gif" class="kg-image" alt="delete-lambda" width="600" height="204" loading="lazy"><figcaption>Como remover as funções AWS Lambda que criamos nesta demonstração</figcaption></figure><h2 id="para-concluir"><strong>Para concluir</strong></h2><p>As funções AWS Lambda são uma ferramenta muito útil para realizar todos os tipos de tarefas em sua conta da AWS. Você pode, basicamente, obter notificações de qualquer mudança nos recursos da AWS através dos eventos CloudWatch e, então, pode acessar quase todos os serviços usando o AWS SDK. Assim, você pode realizar todos os tipos de tarefas de manutenção e tarefas automatizadas em sua infraestrutura.</p><p><strong>Obrigado pela leitura.</strong></p><p>A autora se chama <a href="https://twitter.com/mavi888uy">Marcia Villalba</a>, <em>advocate </em>de desenvolvimento da AWS e apresentadora de um canal no <a href="https://youtube.com/foobar_codes">YouTube</a> chamado FooBar, onde você encontrará mais de 250 tutoriais em vídeo sobre Serverless, AWS e práticas de engenharia de software.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de aplicação com CRUD em React – como criar uma aplicação de gerenciamento de livros em React do zero ]]>
                </title>
                <description>
                    <![CDATA[ Neste artigo, você construirá uma aplicação de gerenciamento de livros em React do zero. Ao criar essa aplicação, você aprenderá:  1. Como realizar operações de CRUD  2. Como usar o React Router para navegação entre rotas  3. Como usar a API React Context para passar dados através ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/tutorial-de-aplicacao-com-crud-em-react-como-criar-uma-aplicacao-de-gerenciamento-de-livros-em-react-do-zero/</link>
                <guid isPermaLink="false">635fd4357e77d305f28d8607</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Wed, 21 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/book_management.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/react-crud-app-how-to-create-a-book-management-app-from-scratch/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">React CRUD App Tutorial – How to Build a Book Management App in React from Scratch</a>
      </p><p>Neste artigo, você construirá uma aplicação de gerenciamento de livros em React do zero.</p><p>Ao criar essa aplicação, você aprenderá:</p><ol><li>Como realizar operações de CRUD</li><li>Como usar o React Router para navegação entre rotas</li><li>Como usar a API React Context para passar dados através de rotas</li><li>Como criar um hook personalizado em React</li><li>Como armazenar dados em armazenamento local para persistir mesmo após a atualização da página</li><li>Como gerenciar os dados armazenados no armazenamento local usando um hook personalizado</li></ol><p>e muito mais.</p><p>Usaremos hooks do React para construir esta aplicação. Portanto, se você é novo no React Hooks, confira meu artigo <a href="https://levelup.gitconnected.com/an-introduction-to-react-hooks-50281fd961fe?source=friends_link&amp;sk=89baff89ec8bc637e7c13b7554904e54">Introdução ao React Hooks</a> (texto em inglês) para aprender o básico.</p><blockquote><em>Quer aprender Redux desde o início absoluto e construir uma aplicação de pedido de comida a partir do zero? Confira o curso <a href="https://master-redux.yogeshchavan.dev/">Mastering Redux</a>.</em></blockquote><h2 id="configura-o-inicial"><strong>Configuração inicial</strong></h2><p>Crie um projeto utilizando o <code>create-react-app</code>:</p><pre><code class="language-js">npx create-react-app book-management-app
</code></pre><p>Uma vez criado o projeto, exclua todos os arquivos da pasta <code>src</code> e crie os arquivos <code>index.js</code> e <code>styles.scss</code> dentro da pasta <code>src</code>. Além disso, crie as pastas <code>components</code>, <code>context</code>, <code>hooks</code> e <code>router</code> dentro da pasta <code>src</code>.</p><p>Instale as dependências necessárias:</p><pre><code class="language-js">yarn add bootstrap@4.6.0 lodash@4.17.21 react-bootstrap@1.5.2 node-sass@4.14.1 react-router-dom@5.2.0 uuid@8.3.2
</code></pre><p>Abra <code>styles.scss</code> e adicione <a href="https://github.com/myogeshchavan97/react-book-management-app/blob/master/src/styles.scss">este</a> conteúdo a ela.</p><h2 id="como-criar-as-p-ginas-iniciais"><strong>Como criar as páginas iniciais</strong></h2><p>Crie um novo arquivo <code>Header.js</code> dentro da pasta <code>components</code> com o seguinte conteúdo:</p><pre><code class="language-jsx">import React from 'react';
import { NavLink } from 'react-router-dom';

const Header = () =&gt; {
  return (
    &lt;header&gt;
      &lt;h1&gt;Book Management App&lt;/h1&gt;
      &lt;hr /&gt;
      &lt;div className="links"&gt;
        &lt;NavLink to="/" className="link" activeClassName="active" exact&gt;
          Books List
        &lt;/NavLink&gt;
        &lt;NavLink to="/add" className="link" activeClassName="active"&gt;
          Add Book
        &lt;/NavLink&gt;
      &lt;/div&gt;
    &lt;/header&gt;
  );
};

export default Header;
</code></pre><p>Aqui, adicionamos dois links de navegação usando o componente <code>NavLink</code> do <code>react-router-dom</code>: um para ver uma lista de todos os livros e o outro para adicionar um novo livro.</p><p>Estamos usando o <code>NavLink</code> em vez da tag de âncora (<code>&lt;a /&gt;</code>). Portanto, a página não será atualizada quando um usuário clicar em qualquer um dos links.</p><p>Crie um arquivo chamado <code>BooksList.js</code> dentro da pasta <code>components</code> com o seguinte conteúdo:</p><pre><code class="language-js">import React from 'react';

const BooksList = () =&gt; {
  return &lt;h2&gt;List of books&lt;/h2&gt;;
};

export default BooksList;
</code></pre><p>Crie um arquivo chamado <code>AddBook.js</code> dentro da pasta <code>components</code> com o seguinte conteúdo:</p><pre><code class="language-jsx">import React from 'react';
import BookForm from './BookForm';

const AddBook = () =&gt; {
  const handleOnSubmit = (book) =&gt; {
    console.log(book);
  };

  return (
    &lt;React.Fragment&gt;
      &lt;BookForm handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/React.Fragment&gt;
  );
};

export default AddBook;
</code></pre><p>Neste arquivo, exibimos um componente <code>BookForm</code> (formulário de livros, que ainda não criamos).</p><p>Para o componente <code>BookForm</code>, passamos o método <code>handleOnSubmit</code> para que possamos fazer o processamento mais tarde, quando enviarmos o formulário.</p><p>Agora, crie um arquivo <code>BookForm.js</code> dentro da pasta <code>components</code> com o seguinte conteúdo:</p><pre><code class="language-jsx">import React, { useState } from 'react';
import { Form, Button } from 'react-bootstrap';
import { v4 as uuidv4 } from 'uuid';

const BookForm = (props) =&gt; {
  const [book, setBook] = useState({
    bookname: props.book ? props.book.bookname : '',
    author: props.book ? props.book.author : '',
    quantity: props.book ? props.book.quantity : '',
    price: props.book ? props.book.price : '',
    date: props.book ? props.book.date : ''
  });

  const [errorMsg, setErrorMsg] = useState('');
  const { bookname, author, price, quantity } = book;

  const handleOnSubmit = (event) =&gt; {
    event.preventDefault();
    const values = [bookname, author, price, quantity];
    let errorMsg = '';

    const allFieldsFilled = values.every((field) =&gt; {
      const value = `${field}`.trim();
      return value !== '' &amp;&amp; value !== '0';
    });

    if (allFieldsFilled) {
      const book = {
        id: uuidv4(),
        bookname,
        author,
        price,
        quantity,
        date: new Date()
      };
      props.handleOnSubmit(book);
    } else {
      errorMsg = 'Please fill out all the fields.';
    }
    setErrorMsg(errorMsg);
  };

  const handleInputChange = (event) =&gt; {
    const { name, value } = event.target;
    switch (name) {
      case 'quantity':
        if (value === '' || parseInt(value) === +value) {
          setBook((prevState) =&gt; ({
            ...prevState,
            [name]: value
          }));
        }
        break;
      case 'price':
        if (value === '' || value.match(/^\d{1,}(\.\d{0,2})?$/)) {
          setBook((prevState) =&gt; ({
            ...prevState,
            [name]: value
          }));
        }
        break;
      default:
        setBook((prevState) =&gt; ({
          ...prevState,
          [name]: value
        }));
    }
  };

  return (
    &lt;div className="main-form"&gt;
      {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
      &lt;Form onSubmit={handleOnSubmit}&gt;
        &lt;Form.Group controlId="name"&gt;
          &lt;Form.Label&gt;Book Name&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="text"
            name="bookname"
            value={bookname}
            placeholder="Enter name of book"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Form.Group controlId="author"&gt;
          &lt;Form.Label&gt;Book Author&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="text"
            name="author"
            value={author}
            placeholder="Enter name of author"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Form.Group controlId="quantity"&gt;
          &lt;Form.Label&gt;Quantity&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="number"
            name="quantity"
            value={quantity}
            placeholder="Enter available quantity"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Form.Group controlId="price"&gt;
          &lt;Form.Label&gt;Book Price&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="text"
            name="price"
            value={price}
            placeholder="Enter price of book"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Button variant="primary" type="submit" className="submit-btn"&gt;
          Submit
        &lt;/Button&gt;
      &lt;/Form&gt;
    &lt;/div&gt;
  );
};

export default BookForm;
</code></pre><p>Vamos entender o que estamos fazendo aqui.</p><p>Inicialmente, definimos um estado como um objeto usando o hook <code>useState</code> para armazenar todos os detalhes inseridos deste modo:</p><pre><code class="language-js">const [book, setBook] = useState({
    bookname: props.book ? props.book.bookname : '',
    author: props.book ? props.book.author : '',
    quantity: props.book ? props.book.quantity : '',
    price: props.book ? props.book.price : '',
    date: props.book ? props.book.date : ''
  });
</code></pre><p>Como usaremos o mesmo componente <code>BookForm</code> para adicionar e editar o livro, verificamos primeiro se a prop <code>book</code> é passada ou não usando o operador ternário.</p><p>Se a prop tiver sido passada, definimos a prop como o valor passado, Do contrário, a definimos como uma string vazia (<code>''</code>).</p><blockquote><em>Não se preocupe se isso parece complicado agora. Você entenderá melhor quando criarmos as funcionalidades iniciais.</em></blockquote><p>Em seguida, adicionamos um <em>state</em> para exibir uma mensagem de erro e usamos a sintaxe de desestruturação da ES6 para nos referirmos a cada uma das propriedades dentro do <em>state</em> assim:</p><pre><code class="language-js">const [errorMsg, setErrorMsg] = useState('');
const { bookname, author, price, quantity } = book;
</code></pre><p>A partir do componente <code>BookForm</code>, retornamos um formulário onde inserimos o nome do livro, autor do livro, quantidade e preço. Usamos o <a href="https://react-bootstrap.github.io/">react-bootstrap</a> para exibir o formulário em um formato mais bonito.</p><p>Cada campo de entrada adicionou um manipulador de eventos <code>onChange</code>, que chama o método <code>handleInputChange</code>.</p><p>Dentro do método <code>handleInputChange</code>, adicionamos uma declaração de mudança para alterar o valor do <em>state</em> com base no campo de entrada que é alterado.</p><p>Quando digitarmos qualquer coisa no campo de entrada <code>quantity</code>, <code>event.target.name</code> será a quantidade para corresponder ao primeiro caso do switch. Dentro desse caso switch, verificamos se o valor inserido é um número inteiro sem um ponto decimal.</p><p>Se for um número inteiro, simplesmente atualizamos o <em>state </em>conforme mostrado abaixo:</p><pre><code class="language-js">if (value === '' || parseInt(value) === +value) {
  setBook((prevState) =&gt; ({
    ...prevState,
    [name]: value
  }));
}
</code></pre><p>Portanto, o usuário não poderá inserir nenhum valor decimal para o campo de entrada <code>quantity</code>.</p><p>Para o caso do switch de <code>price</code>, estamos verificando um número decimal com apenas dois algarismos após a vírgula. Depois, adicionamos uma verificação de expressão regular come esta aparência: <code>value.match(/^\d{1,}(\d{0,2})?$/)</code>.</p><p>Se o valor de <code>price</code> corresponder à expressão regular, atualizamos o <em>state</em>.</p><p><strong>Observação</strong>: tanto para os casos de switch de <code>quantity</code> como de <code>price</code>, verificamos valores vazios como este: <code>value === ''</code>. Isso é para permitir que o usuário exclua totalmente o valor inserido, se necessário.</p><p>Sem essa verificação, o usuário não poderá excluir o valor inserido pressionando <code>Ctrl + A + Delete</code>.</p><p>Para todos os outros campos de entrada, será executado o caso switch que atualizará o <em>state </em>com base no valor inserido pelo usuário.</p><p>Em seguida, uma vez enviado o formulário, o método <code>handleOnSubmit</code> será chamado.</p><p>Dentro desse método, verificamos primeiro se o usuário digitou todos os detalhes usando o método de array <code>every</code>:</p><pre><code class="language-js">const allFieldsFilled = values.every((field) =&gt; {
  const value = `${field}`.trim();
  return value !== '' &amp;&amp; value !== '0';
});
</code></pre><p>O método de array <code>every</code> é um dos métodos de array mais úteis em JavaScript.</p><blockquote><em>Confira o <a href="https://www.freecodecamp.org/news/complete-introduction-to-the-most-useful-javascript-array-methods/">meu artigo aqui</a> para aprender sobre os métodos mais úteis de array JavaScript junto com o seu suporte ao navegador.</em></blockquote><p>Se todos os valores forem preenchidos, criaremos um objeto com eles. Também chamamos o método <code>handleOnSubmit</code> passando livro como argumento. Caso contrário, definimos uma mensagem de erro.</p><p>O método <code>handleOnSubmit</code> é passado como uma prop do componente <code>AddBook</code>.</p><pre><code class="language-js">if (allFieldsFilled) {
  const book = {
    id: uuidv4(),
    bookname,
    author,
    price,
    quantity,
    date: new Date()
  };
  props.handleOnSubmit(book);
} else {
  errorMsg = 'Please fill out all the fields.';
}
</code></pre><p>Note que, para criar uma ID única, chamamos o método <code>uuidv4()</code> a partir do pacote <a href="https://www.npmjs.com/package/uuid">uuid</a> do npm.</p><p>Agora, crie um arquivo <code>AppRouter.js</code> dentro da pasta <code>router</code> com o seguinte conteúdo:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../components/Header';
import AddBook from '../components/AddBook';
import BooksList from '../components/BooksList';

const AppRouter = () =&gt; {
  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route component={BooksList} path="/" exact={true} /&gt;
            &lt;Route component={AddBook} path="/add" /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default AppRouter;
</code></pre><p>Aqui, estabelecemos rotas para vários componentes como <code>BooksList</code> e <code>AddBook</code> usando a biblioteca <code>react-router-dom</code>.</p><blockquote><em>Se você é novo no React Router, confira meu curso gratuito de <a href="https://yogeshchavan1.podia.com/react-router-introduction">Introdução ao React Router</a> (em inglês).</em></blockquote><p>Agora, abra o arquivo <code>src/index.js</code> e adicione o seguinte conteúdo a ele:</p><pre><code class="language-js">import React from 'react';
import ReactDOM from 'react-dom';
import AppRouter from './router/AppRouter';
import 'bootstrap/dist/css/bootstrap.min.css';
import './styles.scss';

ReactDOM.render(&lt;AppRouter /&gt;, document.getElementById('root'));
</code></pre><p>Agora, inicie a aplicação do React, executando o seguinte comando a partir do terminal:</p><pre><code class="language-js">yarn start
</code></pre><p>Você verá a tela a seguir ao acessar a aplicação em <a href="http://localhost:3000/">http://localhost:3000/</a>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/initial_screen.gif" class="kg-image" alt="initial_screen" width="706" height="442" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/add_book.gif" class="kg-image" alt="add_book" width="720" height="450" loading="lazy"></figure><p>Como você pode ver, conseguimos adicionar corretamente um livro e exibi-lo no console.</p><p>Em vez de logar no console, no entanto, vamos adicioná-lo ao armazenamento local.</p><h2 id="como-criar-um-hook-personalizado-para-armazenamento-local"><strong>Como criar um hook personalizado para armazenamento local</strong></h2><p>O armazenamento local é surpreendente. Ele nos permite armazenar facilmente os dados da aplicação no navegador e é uma alternativa aos cookies para o armazenamento de dados.</p><p>A vantagem de se usar o armazenamento local é que os dados serão salvos permanentemente no cache do navegador até que os excluamos manualmente para podermos acessá-los mesmo após a atualização da página. Como você deve saber, os dados armazenados no <em>state</em> do React serão perdidos uma vez que atualizarmos a página.</p><p>Há muitos casos de uso para o armazenamento local. Um deles é para armazenar itens do carrinho de compras para que não sejam excluídos mesmo que atualizemos a página.</p><p>Para adicionar dados ao armazenamento local, usamos o método <code>setItem</code>, fornecendo uma chave e um valor:</p><pre><code class="language-js">localStorage.setItem(key, value)
</code></pre><blockquote><em>Tanto a chave quanto o valor precisam ser strings. Podemos, contudo, armazenar o objeto JSON também usando o método <code>JSON.stringify</code>.</em></blockquote><p>Para aprender em detalhes sobre o armazenamento local e sobre suas diversas aplicações, <a href="https://javascript.plainenglish.io/everything-you-need-to-know-about-html5-local-storage-and-session-storage-479c63415c0a?source=friends_link&amp;sk=f429aa5008683a3b0359db43f976efb3">confira este artigo</a> (em inglês).</p><p>Crie um arquivo <code>useLocalStorage.js</code> dentro da pasta <code>hooks</code> com o seguinte conteúdo:</p><pre><code class="language-jsx">import { useState, useEffect } from 'react';

const useLocalStorage = (key, initialValue) =&gt; {
  const [value, setValue] = useState(() =&gt; {
    try {
      const localValue = window.localStorage.getItem(key);
      return localValue ? JSON.parse(localValue) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  useEffect(() =&gt; {
    window.localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
};

export default useLocalStorage;
</code></pre><p>Aqui, usamos um hook <code>useLocalStorage</code>, que aceita uma <code>key</code> e um <code>initialValue</code>.</p><p>Para declarar o <em>state </em>usando o hook <code>useState</code>, estamos usando <a href="https://reactjs.org/docs/hooks-reference.html#lazy-initial-state">inicialização preguiçosa</a> (em inglês).</p><p>Assim, o código dentro da função passada para <code>useState</code> será executado apenas uma vez, mesmo que o hook <code>useLocalStorage</code> seja chamado várias vezes em cada renderização da aplicação.</p><p>Então, inicialmente, estamos verificando se existe algum valor no armazenamento local com a <code>key</code> fornecida e retornamos o valor usando o método <code>JSON.parse</code>:</p><pre><code class="language-js">try {
  const localValue = window.localStorage.getItem(key);
  return localValue ? JSON.parse(localValue) : initialValue;
} catch (error) {
  return initialValue;
}
</code></pre><p>Depois, se houver alguma mudança em <code>key</code> ou em <code>value</code>, atualizaremos o armazenamento local:</p><pre><code class="language-js">useEffect(() =&gt; {
    window.localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);

return [value, setValue];
</code></pre><p>Em seguida, estamos retornando <code>value</code> armazenado no armazenamento local e a função <code>setValue</code> que chamaremos para atualizar os dados do armazenamento local.</p><h2 id="como-usar-o-hook-de-armazenamento-local"><strong>Como usar o hook de armazenamento local</strong></h2><p>Agora, vamos usar este hook chamado <code>useLocalStorage</code> para que possamos adicionar ou remover dados do armazenamento local.</p><p>Abra o arquivo <code>AppRouter.js</code> e use o hook de <code>useLocalStorage</code> dentro do componente:</p><pre><code class="language-js">import useLocalStorage from '../hooks/useLocalStorage';

const AppRouter = () =&gt; {
 const [books, setBooks] = useLocalStorage('books', []);
 
 return (
  ...
 )
}
</code></pre><p>Agora, precisamos passar <code>books</code> e <code>setBooks</code> como props para o componente <code>AddBook</code> para que possamos adicionar o livro ao armazenamento local.</p><p>Portanto, mude a rota a partir deste código:</p><pre><code class="language-jsx">&lt;Route component={AddBook} path="/add" /&gt;
</code></pre><p>para o código abaixo:</p><pre><code class="language-jsx">&lt;Route
  render={(props) =&gt; (
    &lt;AddBook {...props} books={books} setBooks={setBooks} /&gt;
  )}
  path="/add"
/&gt;
</code></pre><p>Aqui, estamos usando o padrão de renderização de props para passar as props padrão do React Router juntamente com <code>books</code> e <code>setBooks</code>.</p><blockquote><em>Confira o meu curso gratuito de </em><a href="https://yogeshchavan1.podia.com/react-router-introduction"><em>Introdução ao React Router</em></a><em> (em inglês) para entender melhor esse padrão de renderização de props e a importância de se usar a palavra-chave <code>render</code> em vez de <code>component</code>.</em></blockquote><p>Seu arquivo <code>AppRouter.js</code> terá agora esta aparência:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../components/Header';
import AddBook from '../components/AddBook';
import BooksList from '../components/BooksList';
import useLocalStorage from '../hooks/useLocalStorage';

const AppRouter = () =&gt; {
  const [books, setBooks] = useLocalStorage('books', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route component={BooksList} path="/" exact={true} /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;AddBook {...props} books={books} setBooks={setBooks} /&gt;
              )}
              path="/add"
            /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default AppRouter;
</code></pre><p>Agora, abra <code>AddBook.js</code> e substitua o seu conteúdo com o seguinte código:</p><pre><code class="language-jsx">import React from 'react';
import BookForm from './BookForm';

const AddBook = ({ history, books, setBooks }) =&gt; {
  const handleOnSubmit = (book) =&gt; {
    setBooks([book, ...books]);
    history.push('/');
  };

  return (
    &lt;React.Fragment&gt;
      &lt;BookForm handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/React.Fragment&gt;
  );
};

export default AddBook;
</code></pre><p>Primeiro, usamos a sintaxe de desestruturação da ES6 para acessar as props <code>history</code>, <code>books</code> e <code>setBooks</code> no componente.</p><p>A prop <code>history</code> é passada automaticamente pelo React Router a cada componente mencionado na <code>&lt;Route /&gt;</code>. Passamos as props <code>books</code> e <code>setBooks</code> do arquivo <code>AppRouter.js</code>.</p><p>Armazenamos todos os livros adicionados em um array. Dentro do método <code>handleOnSubmit</code>, chamamos a função <code>setBooks</code> passando um array ao adicionar primeiro um livro recém-adicionado e depois fazendo o spread de todos os livros já adicionados no array <code>books</code>, como mostrado abaixo:</p><pre><code class="language-js">setBooks([book, ...books]);
</code></pre><p>Aqui, adicionamos primeiro o livro recém-adicionado e, depois, fazemos o spread dos livros já adicionados, pois queremos que o último livro seja exibido primeiro quando mostrarmos a lista de livros mais tarde.</p><p>Você, no entanto, pode mudar a ordem se quiser:</p><pre><code class="language-js">setBooks([...books, book]);
</code></pre><p>Isto adicionará o livro recém-adicionado no final de todos os livros já adicionados.</p><p>Podemos usar o operador spread, pois sabemos que <code>books</code> é um array (que iniciamos como um array vazio [] no arquivo <code>AppRouter.js</code>, como mostrado abaixo):</p><pre><code class="language-js"> const [books, setBooks] = useLocalStorage('books', []);
</code></pre><p>Então, uma vez que o livro é adicionado ao armazenamento local chamando o método <code>setBooks</code>, dentro do método <code>handleOnSubmit</code>, estamos redirecionando o usuário para a página <code>Books List</code> usando o método <code>history.push</code>:</p><pre><code class="language-js">history.push('/');
</code></pre><p>Agora, vamos verificar se conseguimos salvar ou não os livros no armazenamento local.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/added_local_storage.gif" class="kg-image" alt="added_local_storage" width="692" height="432" loading="lazy"></figure><p>Como você pode ver, o livro está sendo corretamente adicionado ao armazenamento local (e você pode confirmar isso na aba <em>Applications</em> das ferramentas de desenvolvedor do Chrome).</p><h2 id="como-exibir-os-livros-adicionados-na-interface-de-usu-rio"><strong>Como exibir os livros adicionados na interface de usuário</strong></h2><p>Agora, vamos exibir os livros adicionados na UI (interface do usuário) no menu de <code>Books List</code>.</p><p>Abra o <code>AppRouter.js</code> e passe <code>books</code> e <code>setBooks</code> como props para o componente <code>BooksList</code>.</p><p>O seu arquivo <code>AppRouter.js</code> terá esta aparência agora:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../components/Header';
import AddBook from '../components/AddBook';
import BooksList from '../components/BooksList';
import useLocalStorage from '../hooks/useLocalStorage';

const AppRouter = () =&gt; {
  const [books, setBooks] = useLocalStorage('books', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;BooksList {...props} books={books} setBooks={setBooks} /&gt;
              )}
              path="/"
              exact={true}
            /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;AddBook {...props} books={books} setBooks={setBooks} /&gt;
              )}
              path="/add"
            /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default AppRouter;
</code></pre><p>Aqui, acabamos de alterar a primeira rota relacionada ao componente <code>BooksList</code>.</p><p>Agora, crie um arquivo <code>Book.js</code> dentro da pasta <code>components</code> com o seguinte conteúdo:</p><pre><code class="language-jsx">import React from 'react';
import { Button, Card } from 'react-bootstrap';

const Book = ({
  id,
  bookname,
  author,
  price,
  quantity,
  date,
  handleRemoveBook
}) =&gt; {
  return (
    &lt;Card style={{ width: '18rem' }} className="book"&gt;
      &lt;Card.Body&gt;
        &lt;Card.Title className="book-title"&gt;{bookname}&lt;/Card.Title&gt;
        &lt;div className="book-details"&gt;
          &lt;div&gt;Author: {author}&lt;/div&gt;
          &lt;div&gt;Quantity: {quantity} &lt;/div&gt;
          &lt;div&gt;Price: {price} &lt;/div&gt;
          &lt;div&gt;Date: {new Date(date).toDateString()}&lt;/div&gt;
        &lt;/div&gt;
        &lt;Button variant="primary"&gt;Edit&lt;/Button&gt;{' '}
        &lt;Button variant="danger" onClick={() =&gt; handleRemoveBook(id)}&gt;
          Delete
        &lt;/Button&gt;
      &lt;/Card.Body&gt;
    &lt;/Card&gt;
  );
};

export default Book;
</code></pre><p>Agora, abra o arquivo <code>BooksList.js</code> e substitua o seu conteúdo pelo seguinte código:</p><pre><code class="language-jsx">import React from 'react';
import _ from 'lodash';
import Book from './Book';

const BooksList = ({ books, setBooks }) =&gt; {

  const handleRemoveBook = (id) =&gt; {
    setBooks(books.filter((book) =&gt; book.id !== id));
  };

  return (
    &lt;React.Fragment&gt;
      &lt;div className="book-list"&gt;
        {!_.isEmpty(books) ? (
          books.map((book) =&gt; (
            &lt;Book key={book.id} {...book} handleRemoveBook={handleRemoveBook} /&gt;
          ))
        ) : (
          &lt;p className="message"&gt;No books available. Please add some books.&lt;/p&gt;
        )}
      &lt;/div&gt;
    &lt;/React.Fragment&gt;
  );
};

export default BooksList;
</code></pre><p>Neste arquivo, estamos percorrendo <code>books</code>em um laço usando o método de array <code>map</code> e passando os livros como uma prop para o componente <code>Book</code>.</p><p>Note que também estamos passando a função <code>handleRemoveBook</code> como uma prop para que possamos excluir qualquer livro que queiramos.</p><p>Dentro da função <code>handleRemoveBook</code>, estamos chamando a função <code>setBooks</code> usando o método de array <code>filter</code> para manter somente os livros que não correspondem ao ID do livro fornecido.</p><pre><code class="language-js">const handleRemoveBook = (id) =&gt; {
    setBooks(books.filter((book) =&gt; book.id !== id));
};
</code></pre><p>Agora, se você verificar a aplicação acessando <a href="http://localhost:3000/">http://localhost:3000/</a>, poderá ver o livro adicionado na interface do usuário.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/list_page.png" class="kg-image" alt="list_page" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/list_page.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/list_page.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/list_page.png 1426w" sizes="(min-width: 1200px) 1200px" width="1426" height="616" loading="lazy"></figure><p>Vamos adicionar outro livro para verificar todo o fluxo.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/add_delete.gif" class="kg-image" alt="add_delete" width="692" height="432" loading="lazy"></figure><p>Como você pode ver, quando adicionamos um novo livro, somos redirecionados para a página da lista onde podemos excluir o livro. Você pode ver que ele é instantaneamente excluído da UI, bem como do armazenamento local.</p><p>Quando atualizamos a página, além disso, os dados não se perdem. Esse é o poder do armazenamento local.</p><h2 id="como-editar-um-livro"><strong>Como editar um livro</strong></h2><p>Já temos a funcionalidade de adicionar e excluir os livros. Agora, vamos adicionar um modo de editar os livros que temos.</p><p>Abra <code>Book.js</code> e mude o código abaixo:</p><pre><code class="language-jsx">&lt;Button variant="primary"&gt;Edit&lt;/Button&gt;{' '}
</code></pre><p>para este código:</p><pre><code class="language-jsx">&lt;Button variant="primary" onClick={() =&gt; history.push(`/edit/${id}`)}&gt;
  Edit
&lt;/Button&gt;{' '}
</code></pre><p>Aqui, adicionamos um manipulador de eventos <code>onClick</code> para redirecionar o usuário para a rota <code>/edit/id_do_livro</code> quando clicamos no botão de edição.</p><p>Não temos, entretanto, acesso ao objeto <code>history</code> no componente <code>Book</code>, pois a prop <code>history</code> é passada somente aos componentes que são mencionados em <code>&lt;Route /&gt;</code>.</p><p>Estamos renderizando o componente <code>Book</code> dentro do componente <code>BookList</code> para que possamos ter acesso a <code>history</code> somente dentro do componente <code>BookList</code>. Então, podemos passá-la como uma prop ao componente <code>Book</code>.</p><p>Em vez disso, no entanto, o React Router oferece uma maneira fácil de usar o hook <code>useHistory</code>.</p><p>Importe o hook <code>useHistory</code> no topo do arquivo <code>Book.js</code>:</p><pre><code class="language-js">import { useHistory } from 'react-router-dom';
</code></pre><p>e, dentro do componente <code>Book</code>, chame o hook <code>useHistory</code>.</p><pre><code class="language-js">const Book = ({
  id,
  bookname,
  author,
  price,
  quantity,
  date,
  handleRemoveBook
}) =&gt; {
  const history = useHistory();
  ...
}
</code></pre><p>Agora, temos acesso ao objeto <code>history</code> dentro do componente <code>Book</code>.</p><p>O arquivo <code>Book.js</code> terá agora este aparência:</p><pre><code class="language-jsx">import React from 'react';
import { Button, Card } from 'react-bootstrap';
import { useHistory } from 'react-router-dom';

const Book = ({
  id,
  bookname,
  author,
  price,
  quantity,
  date,
  handleRemoveBook
}) =&gt; {
  const history = useHistory();

  return (
    &lt;Card style={{ width: '18rem' }} className="book"&gt;
      &lt;Card.Body&gt;
        &lt;Card.Title className="book-title"&gt;{bookname}&lt;/Card.Title&gt;
        &lt;div className="book-details"&gt;
          &lt;div&gt;Author: {author}&lt;/div&gt;
          &lt;div&gt;Quantity: {quantity} &lt;/div&gt;
          &lt;div&gt;Price: {price} &lt;/div&gt;
          &lt;div&gt;Date: {new Date(date).toDateString()}&lt;/div&gt;
        &lt;/div&gt;
        &lt;Button variant="primary" onClick={() =&gt; history.push(`/edit/${id}`)}&gt;
          Edit
        &lt;/Button&gt;{' '}
        &lt;Button variant="danger" onClick={() =&gt; handleRemoveBook(id)}&gt;
          Delete
        &lt;/Button&gt;
      &lt;/Card.Body&gt;
    &lt;/Card&gt;
  );
};

export default Book;
</code></pre><p>Crie um arquivo chamado <code>EditBook.js</code> dentro da pasta <code>components</code> com o seguinte conteúdo:</p><pre><code class="language-jsx">import React from 'react';
import BookForm from './BookForm';
import { useParams } from 'react-router-dom';

const EditBook = ({ history, books, setBooks }) =&gt; {
  const { id } = useParams();
  const bookToEdit = books.find((book) =&gt; book.id === id);

  const handleOnSubmit = (book) =&gt; {
    const filteredBooks = books.filter((book) =&gt; book.id !== id);
    setBooks([book, ...filteredBooks]);
    history.push('/');
  };

  return (
    &lt;div&gt;
      &lt;BookForm book={bookToEdit} handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/div&gt;
  );
};

export default EditBook;
</code></pre><p>Aqui, para o manipulador de eventos <code>onClick</code> do botão Edit, redirecionamos o usuário para a rota <code>/edit/id_do_livro</code> – essa rota, no entanto, ainda não existe. Portanto, vamos criá-la primeiro.</p><p>Abra o <code>AppRouter.js</code> e, antes da tag final de <code>Switch</code>, adicione mais duas rotas:</p><pre><code class="language-jsx">&lt;Switch&gt;
...
&lt;Route
  render={(props) =&gt; (
    &lt;EditBook {...props} books={books} setBooks={setBooks} /&gt;
  )}
  path="/edit/:id"
/&gt;
&lt;Route component={() =&gt; &lt;Redirect to="/" /&gt;} /&gt;
&lt;/Switch&gt;
</code></pre><p>A primeira rota é para o componente <code>EditBook</code>. Aqui, o caminho é definido como <code>/edit/:id</code> onde <code>:id</code> representa qualquer id aleatória.</p><p>A segunda rota serve para lidar com todas as outras rotas que não correspondem a nenhuma das rotas mencionadas.</p><p>Assim, se acessarmos qualquer rota aleatória, como <code>/help</code> ou <code>/contact</code>, redirecionaremos o usuário para a rota <code>/</code>, que é a do componente <code>BooksList</code>.</p><p>O arquivo <code>AppRouter.js</code> terá agora esta aparência:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../components/Header';
import AddBook from '../components/AddBook';
import BooksList from '../components/BooksList';
import useLocalStorage from '../hooks/useLocalStorage';

const AppRouter = () =&gt; {
  const [books, setBooks] = useLocalStorage('books', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;BooksList {...props} books={books} setBooks={setBooks} /&gt;
              )}
              path="/"
              exact={true}
            /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;AddBook {...props} books={books} setBooks={setBooks} /&gt;
              )}
              path="/add"
            /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;EditBook {...props} books={books} setBooks={setBooks} /&gt;
              )}
              path="/edit/:id"
            /&gt;
            &lt;Route component={() =&gt; &lt;Redirect to="/" /&gt;} /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default AppRouter;
</code></pre><p>Vamos verificar a funcionalidade de edição do aplicativo.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/edit_book.gif" class="kg-image" alt="edit_book" width="692" height="432" loading="lazy"></figure><p>Como você pode ver, somos capazes de editar o livro com sucesso. Vamos entender como isso funciona.</p><p>Primeiro, dentro do arquivo <code>AppRouter.js</code>, temos uma rota como esta:</p><pre><code class="language-jsx">&lt;Route
  render={(props) =&gt; (
    &lt;EditBook {...props} books={books} setBooks={setBooks} /&gt;
  )}
  path="/edit/:id"
/&gt;
</code></pre><p>e dentro do arquivo <code>Book.js</code>, temos um botão de edição, como este:</p><pre><code class="language-jsx">&lt;Button variant="primary" onClick={() =&gt; history.push(`/edit/${id}`)}&gt;
  Edit
&lt;/Button&gt;
</code></pre><p>Assim, sempre que clicarmos no botão Edit para qualquer um dos livros, estamos redirecionando o usuário para o componente <code>EditBook</code> usando o método <code>history.push</code>, passando o id do livro a ser editado.</p><p>Depois, dentro do componente <code>EditBook</code>, usamos o hook <code>useParams</code> fornecido pelo <code>react-router-dom</code> para acessar <code>props.params.id</code>.</p><p>Portanto, as duas linhas abaixo são idênticas.</p><pre><code class="language-js">const { id } = useParams();

// A linha de código acima equivale à linha abaixo

const { id } = props.match.params;
</code></pre><p>Uma vez que tenhamos obtido essa identificação, usaremos o método de array <code>find</code> para encontrar o livro específico a partir da lista de livros com a id correspondente fornecida.</p><pre><code class="language-js">const bookToEdit = books.find((book) =&gt; book.id === id);
</code></pre><p>e esse livro específico é passado para o componente <code>BookForm</code> como uma prop <code>book</code>:</p><pre><code class="language-jsx">&lt;BookForm book={bookToEdit} handleOnSubmit={handleOnSubmit} /&gt;
</code></pre><p>Dentro do componente <code>BookForm</code>, definimos o <em>state </em>como mostrado abaixo:</p><pre><code class="language-js">const [book, setBook] = useState({
  bookname: props.book ? props.book.bookname : '',
  author: props.book ? props.book.author : '',
  quantity: props.book ? props.book.quantity : '',
  price: props.book ? props.book.price : '',
  date: props.book ? props.book.date : ''
});
</code></pre><p>Aqui, verificamos se a prop <code>book</code> existe. Se existir, usamos os detalhes do livro passado como uma prop. Caso contrário, inicializamos o <em>state </em>com um valor vazio (<code>''</code>) para cada propriedade.</p><p>Cada um dos elementos de entrada forneceu uma prop <code>value</code>, que estamos definindo a partir do <em>state</em>,<em> </em>deste modo:</p><pre><code class="language-jsx">&lt;Form.Control
  ...
  value={bookname}
  ...
/&gt;
</code></pre><p>Podemos, porém, melhorar um pouco a sintaxe de <code>useState</code> dentro do componente <code>BookForm</code>.</p><p>Ao invés de definir diretamente um objeto para o hook <code>useState</code>, podemos usar a inicialização preguiçosa como fizemos no arquivo <code>useLocalStorage.js</code>.</p><p>Assim, mude o código abaixo:</p><pre><code class="language-js">const [book, setBook] = useState({
  bookname: props.book ? props.book.bookname : '',
  author: props.book ? props.book.author : '',
  quantity: props.book ? props.book.quantity : '',
  price: props.book ? props.book.price : '',
  date: props.book ? props.book.date : ''
});
</code></pre><p>para este código:</p><pre><code class="language-js">const [book, setBook] = useState(() =&gt; {
  return {
    bookname: props.book ? props.book.bookname : '',
    author: props.book ? props.book.author : '',
    quantity: props.book ? props.book.quantity : '',
    price: props.book ? props.book.price : '',
    date: props.book ? props.book.date : ''
  };
});
</code></pre><p>Em função dessa mudança, o código para definir o <em>state </em>não será executado em cada renderização da aplicação. Ele será executado apenas uma vez quando o componente for montado.</p><blockquote><em>Note que a renderização do componente acontece em cada state ou mudança de prop</em>.</blockquote><p>Se você verificar a aplicação, verá que a aplicação funciona exatamente como antes, sem qualquer problema. Nós apenas melhoramos um pouco o desempenho da aplicação.</p><h2 id="como-usar-a-api-react-context"><strong>Como usar a API React Context</strong></h2><p>Agora, terminamos de construir toda a funcionalidade da aplicação. Se você, no entanto, verificar o arquivo <code>AppRouter.js</code>, verá que cada Rota parece um pouco complicada. Isso ocorre porque estamos passando as mesmos props <code>books</code> e <code>setBooks</code> para cada um dos componentes, usando o padrão de renderização de props.</p><p>Assim, podemos usar a API React Context para simplificar esse código.</p><blockquote><em>Note que este é um passo opcional. Você não precisa usar a API React Context, já que estamos passando as props com apenas um nível de profundidade, o código atual está funcionando perfeitamente bem e não usamos nenhuma abordagem errada para passar as props</em></blockquote><p>Apenas para tornar o código do Router mais simples e para dar uma ideia de como aproveitar o poder da API React Context, usaremos a API em nossa aplicação.</p><p>Crie um arquivo <code>BooksContext.js</code> dentro da pasta de contexto com o seguinte conteúdo:</p><pre><code class="language-js">import React from 'react';

const BooksContext = React.createContext();

export default BooksContext;
</code></pre><p>Agora, dentro do arquivo <code>AppRouter.js</code>, importe o contexto exportado acima.</p><pre><code class="language-js">import BooksContext from '../context/BooksContext';
</code></pre><p>e substitua o componente <code>AppRouter</code> pelo código abaixo:</p><pre><code class="language-jsx">const AppRouter = () =&gt; {
  const [books, setBooks] = useLocalStorage('books', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;BooksContext.Provider value={{ books, setBooks }}&gt;
            &lt;Switch&gt;
              &lt;Route component={BooksList} path="/" exact={true} /&gt;
              &lt;Route component={AddBook} path="/add" /&gt;
              &lt;Route component={EditBook} path="/edit/:id" /&gt;
              &lt;Route component={() =&gt; &lt;Redirect to="/" /&gt;} /&gt;
            &lt;/Switch&gt;
          &lt;/BooksContext.Provider&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};
</code></pre><p>Aqui, convertemos o padrão de renderização das props para as rotas normais e adicionamos todo o bloco de <code>Switch</code> dentro do componente <code>BooksContext.Provider</code> assim:</p><pre><code class="language-jsx">&lt;BooksContext.Provider value={{ books, setBooks }}&gt;
 &lt;Switch&gt;
 ...
 &lt;/Switch&gt;
&lt;/BooksContext.Provider&gt;
</code></pre><p>Aqui, para o componente <code>BooksContext.Provider</code>, fornecemos uma prop <code>value</code> ao passar os dados que queremos acessar dentro dos componentes mencionados em Route.</p><p>Assim, agora, cada componente declarado como parte da Route poderá acessar <code>books</code> e <code>setBooks</code> através da API React Context.</p><p>Agora, abra o arquivo <code>BooksList.js</code> e remova as props <code>books</code> e <code>setBooks</code> que estão desestruturadas, pois não estamos mais passando diretamente as props.</p><p>Importe o <code>BooksContext</code> e <code>useContext</code> na parte superior do arquivo:</p><pre><code class="language-js">import React, { useContext } from 'react';
import BooksContext from '../context/BooksContext';
</code></pre><p>Acima da função <code>handleRemoveBook</code>, adicione o seguinte código:</p><pre><code class="language-js">const { books, setBooks } = useContext(BooksContext);
</code></pre><p>Aqui, estamos retirando os livros e os adereços de <code>BooksContext</code> usando o hook <code>useContext</code>.</p><p>O arquivo <code>BooksList.js</code> terá agora esta aparência:</p><pre><code class="language-jsx">import React, { useContext } from 'react';
import _ from 'lodash';
import Book from './Book';
import BooksContext from '../context/BooksContext';

const BooksList = () =&gt; {
  const { books, setBooks } = useContext(BooksContext);

  const handleRemoveBook = (id) =&gt; {
    setBooks(books.filter((book) =&gt; book.id !== id));
  };

  return (
    &lt;React.Fragment&gt;
      &lt;div className="book-list"&gt;
        {!_.isEmpty(books) ? (
          books.map((book) =&gt; (
            &lt;Book key={book.id} {...book} handleRemoveBook={handleRemoveBook} /&gt;
          ))
        ) : (
          &lt;p className="message"&gt;No books available. Please add some books.&lt;/p&gt;
        )}
      &lt;/div&gt;
    &lt;/React.Fragment&gt;
  );
};

export default BooksList;
</code></pre><p>Agora, faça mudanças similares no arquivo <code>AddBook.js</code>.</p><p>O arquivo <code>AddBooks.js</code> terá agora esta aparência:</p><pre><code class="language-jsx">import React, { useContext } from 'react';
import BookForm from './BookForm';
import BooksContext from '../context/BooksContext';

const AddBook = ({ history }) =&gt; {
  const { books, setBooks } = useContext(BooksContext);

  const handleOnSubmit = (book) =&gt; {
    setBooks([book, ...books]);
    history.push('/');
  };

  return (
    &lt;React.Fragment&gt;
      &lt;BookForm handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/React.Fragment&gt;
  );
};

export default AddBook;
</code></pre><p>Note que, aqui, ainda estamos usando a desestruturação para a prop <code>history</code>. Apenas removemos <code>books</code> e <code>setBooks</code> da sintaxe de desestruturação.</p><p>Agora, faça mudanças similares no arquivo <code>EditBook.js</code>.</p><p>O arquivo <code>EditBooks.js</code> terá agora esta aparência:</p><pre><code class="language-jsx">import React, { useContext } from 'react';
import BookForm from './BookForm';
import { useParams } from 'react-router-dom';
import BooksContext from '../context/BooksContext';

const EditBook = ({ history }) =&gt; {
  const { books, setBooks } = useContext(BooksContext);
  const { id } = useParams();
  const bookToEdit = books.find((book) =&gt; book.id === id);

  const handleOnSubmit = (book) =&gt; {
    const filteredBooks = books.filter((book) =&gt; book.id !== id);
    setBooks([book, ...filteredBooks]);
    history.push('/');
  };

  return (
    &lt;div&gt;
      &lt;BookForm book={bookToEdit} handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/div&gt;
  );
};

export default EditBook;
</code></pre><p>Se você verificar a aplicação, verá que ela funciona exatamente como antes, mas agora estamos usando a API React Context.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/edit_delete.gif" class="kg-image" alt="edit_delete" width="692" height="432" loading="lazy"></figure><p>Se você quiser entender a API React Context em detalhes, confira <a href="https://medium.com/swlh/what-is-context-api-in-react-and-how-to-use-it-in-react-app-dedbcdd78801?source=friends_link&amp;sk=5ea2b1078e16173036b95c477cde369c"></a><a href="https://medium.com/swlh/what-is-context-api-in-react-and-how-to-use-it-in-react-app-dedbcdd78801?source=friends_link&amp;sk=5ea2b1078e16173036b95c477cde369c">este</a> <a href="https://medium.com/swlh/what-is-context-api-in-react-and-how-to-use-it-in-react-app-dedbcdd78801?source=friends_link&amp;sk=5ea2b1078e16173036b95c477cde369c">artigo</a> (texto em inglês).</p><h3 id="obrigado-pela-leitura-"><strong>Obrigado pela leitura!</strong></h3><p>Você pode encontrar o código-fonte completo para esta aplicação <a href="https://github.com/myogeshchavan97/react-book-management-app">neste repositório</a>.</p><p>Quer aprender todas as características do ES6+ em detalhes, incluindo let e const, promises, vários métodos de promises, desestruturação de arrays e objetos, arrow functions, async/await, importação e exportação e muito mais?</p><p><strong>Confira o livro do autor, <a href="https://modernjavascript.yogeshchavan.dev/">Mastering Modern JavaScript</a> (em inglês). Esse livro cobre todos os pré-requisitos para aprender React e ajuda você a se tornar melhor em JavaScript e React.</strong></p><blockquote>Confira uma prévia do conteúdo do livro gratuitamente <a href="https://www.freecodecamp.org/news/learn-modern-javascript/">aqui</a> (em inglês).</blockquote><p>Além disso, você pode conferir o curso <strong>gratuito</strong> do autor, <a href="https://yogeshchavan1.podia.com/react-router-introduction">Introdução ao React Router</a> (em inglês) para aprender React Router do zero.</p><p>Deseja manter-se atualizado com o conteúdo regular sobre JavaScript, React, Node.js? <a href="https://www.linkedin.com/in/yogesh-chavan97/">Siga o autor no LinkedIn</a>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/banner.jpg" class="kg-image" alt="banner" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/banner.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/banner.jpg 867w" sizes="(min-width: 720px) 720px" width="867" height="291" loading="lazy"></figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A melhor maneira de aprender desenvolvimento em back-end para a web ]]>
                </title>
                <description>
                    <![CDATA[ Meu artigo anterior descreveu como você pode entrar no desenvolvimento em front-end [https://www.freecodecamp.org/news/learn-frontend-web-development/]  (texto em inglês). Ele também discutiu como o front-end pode ser um lugar cheio de perigos – pisar no lugar errado e você ficará sobrecarregado com os muitos  frameworks do ecossistema do JavaScript. Neste artigo, ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/a-melhor-maneira-de-aprender-desenvolvimento-em-backend-para-a-web/</link>
                <guid isPermaLink="false">63724e561c6e8805bd494d9a</guid>
                
                    <category>
                        <![CDATA[ Desenvolvimento Back-end ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Tue, 20 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/5f9c9bab740569d1a4ca2d39.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/learn-backend-development/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The Best Way to Learn Backend Web Development</a>
      </p><p>Meu artigo anterior descreveu <a href="https://www.freecodecamp.org/news/learn-frontend-web-development/">como você pode entrar no desenvolvimento em <em>front-end</em></a> (texto em inglês). Ele também discutiu como o <em>front-end</em> pode ser um lugar cheio de perigos – pisar no lugar errado e você ficará sobrecarregado com os muitos <em>frameworks </em>do ecossistema do JavaScript.</p><p>Neste artigo, vamos ver como você pode entrar no desenvolvimento em <em>back-end</em>. Ao longo do caminho, vou responder a algumas das perguntas mais comuns que as pessoas me fazem sobre o assunto.</p><h2 id="o-que-o-desenvolvimento-em-back-end"><strong>O que é o desenvolvimento em </strong><em>back-end</em><strong>?</strong></h2><p>O desenvolvimento em <em>front-end</em> envolve o que um usuário vê na tela quando abre um URL específico de sua propriedade. Mesmo em um ambiente completamente estático (apenas com HTML/CSS), quando alguém abre um site da web, algum servidor no planeta precisa responder a você com esses arquivos HTML e CSS.</p><p>Esse servidor é apenas um computador, como aquele que você mesmo usa para navegar na internet. Ele, no entanto, foi ajustado para o desempenho, não tendo componentes desnecessários como um mouse ou teclado anexado. Ele também fica com milhares de outros computadores, provavelmente em um depósito de dados.</p><p>A programação desses computadores de algum modo especial é chamada de <strong>desenvolvimento em <em>back-end</em></strong>.</p><p>Você pode pensar que o desenvolvimento em <em>back-end</em> é chamado assim porque ele funciona por trás daquilo que o usuário enxerga. Um visitante do seu site nunca realmente "acessa" completamente o <em>back-end</em>. Ele apenas se comunica com o seu servidor, seja diretamente através de portas para acesso muito limitado (como a transferência de arquivos HTML/CSS) ou nem mesmo isso - enterrado profundamente sob CDNs ou firewalls (como no caso do Cloudflare).</p><p>Agora que temos uma compreensão básica do que significa desenvolvimento em <em>back-end</em>, vamos entrar em algumas questões <strong>reais</strong>.</p><h2 id="-necess-rio-o-conhecimento-de-programa-o-em-front-end-para-o-back-end"><strong>É necessário o conhecimento de programação em <em>front-end </em>para o </strong><em>back-end</em><strong>?</strong></h2><p><strong>Resposta curta:</strong> Não.</p><p>O desenvolvimento em <em>back-end</em>, como mencionado acima, envolve a programação de um computador que provavelmente está do outro lado do planeta, responsável por responder ao que seus usuários dizem a partir dos seus próprios computadores.</p><p>Se você é um desenvolvedor em <em>back-end</em> em tempo integral, você realmente não precisa se importar com o que acontece dentro daqueles arquivos HTML, CSS e JavaScript que você envia para o navegador do usuário. Ao invés disso, você tem que se concentrar mais no desempenho do servidor, no código do servidor e na produção.</p><h2 id="o-que-acontece-no-desenvolvimento-em-back-end"><strong>O que acontece no desenvolvimento em </strong><em>back-end</em><strong>?</strong></h2><p>Bem, seguindo os livros, você pode dizer que uma pessoa que programa uma aplicação que pode responder a solicitações HTTP é um desenvolvedor em <em>back-end</em>.</p><p>Na realidade, porém, às vezes, os desenvolvedores em<em> back-end</em> são capazes de fazer muito mais do que apenas escrever scripts de servidor. Eles têm o conhecimento para configurar servidores proxies reversíveis (NGiNX/HAProxy), permitir a compressão e outras formas de acelerar o site, além de configurar um ambiente do Docker de produção.</p><p>Para se qualificar como desenvolvedor em <em>back-end</em>, eu diria que as habilidades mínimas que você precisa são:</p><ol><li>Bom conhecimento sobre uma linguagem de programação na qual você pode escrever servidores HTTP. Exemplos: C#, Java, Node, PHP, Python etc. (há muitas!)</li><li>Gerenciar para hospedagem usando cPanel (tradicional) ou usando o terminal do bash (cloud hosting/tradicional)</li><li>Trabalhar com sistemas de controle de versão (VCS) como o Git para gerenciar e fazer a implantação das <em>builds</em></li></ol><p>Assim como todo jogo vem com especificações mínimas e recomendadas, para os desenvolvedores em <em>back-end</em>, as minhas especificações recomendadas seriam (incluindo as habilidades mínimas):</p><ol><li>NGiNX, para itens de arquivos estáticos e gerenciamento de servidores</li><li>Habilidades de gerenciamento de banco de dados (SQL/NoSQL)</li><li>Segurança do <em>back-end</em> (escrever código seguro e robusto, executar aplicações em contêineres do Docker com privilégios limitados, proteção contra ataques DdoS)</li><li>Balanceamento automático/balanceamento de carga</li></ol><p>Muito bem, já falei muito sobre o necessário para o desenvolvimento em back-end. Como, no entanto, você pode se torna um desenvolvedor em <em>back-end</em>?</p><h2 id="comece-com-os-requisitos-m-nimos"><strong>Comece com os requisitos mínimos</strong></h2><p>Como eu disse, para o <em>back-end</em>, assim como nos jogos, temos um conjunto de requisitos mínimos e requisitos recomendados. Os requisitos mínimos consistem em 3 coisas:</p><h2 id="aprenda-uma-linguagem-de-programa-o-de-back-end"><strong>Aprenda uma linguagem de programação de <em>back-end</em></strong></h2><p>Quando as pessoas aprendem sozinhas, elas geralmente não têm uma equipe ou alguém que possa fazer o desenvolvimento do <em>front-end</em>. Elas estão todas por conta própria. Portanto, muitas vezes, você terá que criar páginas da web e servidores por conta própria, ao menos no início.</p><p>Existem muitas opções de linguagens de programação de <em>back-end</em>. Não consigo pensar em nenhuma linguagem de sistema popular que não suporte servidores HTTP desde o início. A vantagem de se escolher o Node é que suas habilidades de JavaScript do <em>front-end </em>são transferíveis para o <em>back-end</em>.</p><p>No entanto, você pode escolher entre uma variedade de linguagens, como Java, C++, C#, Python, PHP, entre outras.</p><p>Como escolher uma, você pode se perguntar. A resposta é a mesma que foi dada no artigo de desenvolvimento em <em>front-end</em>: você tem que tentar tudo inicialmente e ver qual é aquela que é melhor com você.</p><p>O Node é fácil, já que você deve ter feito a programação em JavaScript para o <em>front-end</em>. Se, no entanto, você é um desenvolvedor Python ou Java, pode achar essas fáceis de entender. Isso depende completamente da sua profissão e do seu gosto.</p><h2 id="aprenda-mais-sobre-como-administrar-a-hospedagem"><strong>Aprenda mais sobre como administrar a hospedagem</strong></h2><p>Já se foram os dias em que você precisava comprar servidores manualmente e configurá-los em sua casa, conectar-se ao provedor e fazer tudo isso você mesmo. Essa é a era da computação em nuvem. Agora, ao hospedar seu site da web, você tem 2 opções, em especial:</p><ol><li>Ir para servidores de hospedagem gerenciada, como a HostGator ou o GoDaddy.</li><li>Ir para provedores de hospedagem em nuvem, como a GCP, a AWS ou a DigitalOcean.</li></ol><p>Qual é a diferença entre os dois? Em ambos os casos, os servidores são de propriedade e operados pelas respectivas empresas. A grande diferença, porém, é que a hospedagem gerenciada é mais amigável para as interfaces gráficas, tem um rico conjunto de ferramentas para ver o sistema de arquivos, monitorar o uso, gerenciar seus e-mails oficiais de domínio, fazer upload/download de arquivos de seu servidor e assim por diante. É, basicamente, uma configuração para pessoas com menos habilidades técnicas.</p><p>Por esse motivo, não recomendo sites gerenciados, como a HostGator ou o GoDaddy, para desenvolvedores experientes. Mesmo assim, pode ser uma boa plataforma para cometer erros e aprender com eles, principalmente porque você normalmente tem planos pré-pagos para eles. Você também terá uma boa interface para gerenciar as coisas, o que não permite que você faça com que suas contas aumentem exponencialmente por acidente.</p><p>Quando, no entanto, você começar a se acostumar, recomendo que você mude para um provedor na nuvem. Isso tira todas as ferramentas legais do cPanel que você usava para gerenciar arquivos e pastas em servidores. Ao mesmo tempo, o desafiará muito a elevar o nível de suas habilidades.</p><p>Hoje, muitos provedores na nuvem também oferecem um teste gratuito decente, para que você possa realmente experimentar a plataforma deles antes de entrar em pleno funcionamento. Eu hospedo meu site para desenvolvedores – o codedamn – na DigitalOcean e acho que ele tem um bom equilíbrio entre complexidade e recursos do site.</p><p>Você pode usar <a href="https://m.do.co/c/2c4c3ec5405a">este link para se inscrever</a> na DigitalOcean e obter <strong>US$ 100 de créditos</strong> <strong>gratuitos</strong>. As instâncias da DigitalOcean custam cerca de US$ 5 por mês. Então, você tem cerca de 20 meses nessa instância. Ótimo negócio, não é?</p><p>De qualquer forma, você pode escolher qualquer provedor na nuvem. Então, é importante aprender a gerenciar o servidor usando apenas a linha de comando usando o ssh nela.</p><h2 id="saiba-mais-sobre-sistemas-de-controle-de-vers-o"><strong>Saiba mais sobre sistemas de controle de versão</strong></h2><p>Existem outras soluções além do Git para SCVs. O Git, porém é a solução mais usada e a mais simples de entender.</p><p>Pessoalmente, pode ser que você não goste do Git de imediato, mas você entenderá porque ele é tão importante no momento em que você começar a trabalhar em equipe, em vários recursos simultaneamente em seu projeto.</p><p>O Git permite que você gerencie o seu fluxo de trabalho utilizando <em>commits </em>e <em>branches</em>. Os <em>commits </em>são como <strong>pontos de verificação</strong> em sua base de código – aqueles para os quais você pode sempre retornar se estragar tudo.</p><p>As<em> branches </em>são como <strong>realidades alternativas</strong> do seu projeto, onde algo completamente diferente poderia acontecer. Essas realidades alternativas podem ser criadas a partir de qualquer ponto no tempo e podem ser mescladas novamente a qualquer momento.</p><p>Se essas realidades puderem ser mescladas com compatibilidade, tudo bem. Se houver algum conflito (como se você estivesse vivo em uma realidade e morto em outra), você terá que fazer uma escolha manualmente. Outras mudanças podem ser mescladas automaticamente.</p><p>O Git é superinteressante. Quando você o dominar, vai querer usá-lo em cada projeto. Você conseguirá manter um histórico do seu trabalho de modo eficiente (ele comprime e armazena apenas a diferença entre os <em>commits</em>).</p><p>Também é possível criar repositórios do Git on-line, em sites como o GitHub, que atua como uma fonte central de verdade para o seu site. Sites como o GitHub podem ser configurados com <em>hooks</em> especiais da web, que podem realmente atualizar o seu site sempre que você adicionar um novo ponto de verificação (um novo <em>commit</em>) sem que você precise ir manualmente ao servidor e atualizá-lo você mesmo.</p><h2 id="tenha-as-habilidades-recomendadas"><strong>Tenha as habilidades recomendadas</strong></h2><p>Eu acredito firmemente em aprender fazendo. A melhor maneira de se fazer algo vem da necessidade ou do interesse. Quando você se considerar suficientemente bom com os requisitos mínimos, é hora de adquirir as habilidades recomendadas. Essas incluem todas as ferramentas, como o Docker e o NGiNX, mencionadas acima.</p><p>O <strong>DevOps</strong> também é algo que se encaixa muito bem com os desenvolvedores em <em>back-end</em>. Você pode tentar explorar o <strong>TravisCI</strong> ou o <strong>CircleCI</strong> para builds automatizadas. Integração e Implantação Contínuas (CI/CD) é um tópico que poderia levar a outro artigo inteiro. Por isso, não vou entrar no assunto. Na verdade, uma vez configurado corretamente, isso lhe poupará uma quantidade ridícula de tempo de desenvolvimento!</p><p>Depois, temos os bancos de dados, que eu coloquei nas habilidades recomendadas. Você vai, contudo, precisar de bancos de dados para praticamente qualquer aplicação que envolva algum tipo de persistência de dados gerada pelo usuário.</p><p>Os bancos de dados são geralmente fáceis de começar a trabalhar, mas mais difíceis de manter e de ajustar corretamente. A melhor maneira de se começar a trabalhar em uma pilha de tecnologia em <em>back-end</em> é ter tudo junto em um único servidor – o código de sua aplicação, os servidores proxy reversos, o banco de dados e assim por diante. Então, conforme você se torna mais proficiente em cada parte, você pode desacoplá-la da lógica de negócios existente.</p><p>Ao fazer isso, você está possibilitando uma arquitetura que pode ser altamente escalonável. Uma aplicação intensiva do banco de dados poderia ter uma solução otimizada para eles. Um site com tráfego intenso deve ter um bom mecanismo de CDN para descarregar ativos estáticos e assim por diante.</p><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>Há muito o que aprender, mas tudo isso é possível se você não desistir. Conte ao autor o que você pensou sobre este artigo através do <a href="https://twitter.com/mehulmpt"><strong>Twitter</strong></a> e do <a href="https://instagram.com/mehulmpt"><strong>Instagram</strong></a> do autor. Ele gostará muito de se conectar com os leitores por lá!</p><p>Além disso, se estiver interessado, confira o <a href="https://codedamn.com"><strong>codedamn</strong></a> – uma plataforma voltada para o desenvolvedor para o aprendizado de tecnologias como o desenvolvimento em <em>back-end</em>! O autor, inclusive, já publicou <a href="https://www.youtube.com/watch?v=IOTL7RqUZEU">um vídeo no YouTube sobre como rodar seu próprio servidor de sites da web simples em apenas 2 minutos</a>! Confira o e diga ao autor o que você acha pelas redes sociais mencionadas acima!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como obter e configurar suas chaves SSH do Git e do GitHub ]]>
                </title>
                <description>
                    <![CDATA[ Se você usa GitHub sem configurar uma chave SSH, não sabe o que está perdendo. Basta pensar que todo esse tempo que você passou inserindo o seu endereço de e-mail e senha no console toda vez que faz um commit poderia ter sido gasto programando. Bem, não mais. Aqui está ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-obter-e-configurar-suas-chaves-ssh-do-git-e-do-github/</link>
                <guid isPermaLink="false">635fac637e77d305f28d83cd</guid>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Mon, 19 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/5f9c9e49740569d1a4ca3c4e.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/git-ssh-how-to/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Get and Configure Your Git and GitHub SSH Keys</a>
      </p><p>Se você usa GitHub sem configurar uma chave SSH, não sabe o que está perdendo. Basta pensar que todo esse tempo que você passou inserindo o seu endereço de e-mail e senha no console toda vez que faz um <em>commit </em>poderia ter sido gasto programando.</p><p>Bem, não mais. Aqui está um guia rápido para gerar e configurar uma chave SSH no GitHub para que você nunca mais tenha que autenticar da maneira antiga.</p><h3 id="verificar-a-exist-ncia-de-uma-chave-ssh"><strong>Verificar a existência de uma chave SSH</strong></h3><p>Primeiro, verifique se você já gerou chaves SSH para a sua máquina. Abra um terminal e digite o seguinte comando:</p><pre><code class="language-shell">ls -al ~/.ssh</code></pre><p>Se você já gerou chaves SSH, você deve ver um resultado semelhante a este:</p><pre><code class="language-sh">-rw-------  1 user_name user_name  1766 Jul  7  2018 id_rsa
-rw-r--r--  1 user_name user_name   414 Jul  7  2018 id_rsa.pub
-rw-------  1 user_name user_name 12892 Feb  5 18:39 known_hosts</code></pre><p>Se suas chaves já existem, pule adiante para a seção <strong>Copiar a sua chave SSH</strong> <strong>pública</strong> abaixo.</p><p>Se você não vê nenhum resultado ou se aquele diretório não existe (você recebe uma mensagem <code>No such file or directory</code>), execute:</p><pre><code class="language-shell">mkdir $HOME/.ssh</code></pre><p>Em seguida, gere um novo conjunto de chaves com:</p><pre><code class="language-shell">ssh-keygen -t rsa -b 4096 -C your@email.com</code></pre><p>Agora, verifique se as suas chaves existem com o comando <code>ls -al ~/.ssh</code> e certifique-se de que o resultado seja similar ao listado acima.</p><p><strong>Observação</strong>: as chaves SSH são sempre geradas como um par de chaves, uma pública (id_rsa.pub) e uma privada (id_rsa). É extremamente importante que você <strong>nunca revele sua chave privada</strong> e <strong>somente use sua chave pública</strong> para coisas como a autenticação no GitHub. Você pode ler mais sobre como os pares de chaves SSH/RSA funcionam <a href="https://www.freecodecamp.org/news/a-top-down-introduction-to-ssh-965f4fadd32e/">aqui</a> (texto em inglês).</p><h3 id="adicionar-a-chave-ssh-ao-ssh-agent">Adicionar a chave SSH ao ssh-agent</h3><p>O <code>ssh-agent</code> é um programa que começa quando você faz o login e armazena as suas chaves privadas. Para que funcione corretamente, ele precisa estar funcionando e ter uma cópia da sua chave privada.</p><p>Primeiro, certifique-se de que o <code>ssh-agent</code> está funcionando com:</p><pre><code class="language-shell">eval "$(ssh-agent -s)" # for Mac and Linux</code></pre><p>ou:</p><pre><code class="language-shell">eval `ssh-agent -s`
ssh-agent -s # for Windows</code></pre><p>Em seguida, adicione a sua chave privada ao <code>ssh-agent</code> com:</p><pre><code class="language-shell">ssh-add ~/.ssh/id_rsa</code></pre><h3 id="copiar-a-sua-chave-ssh-p-blica"><strong>Copiar a sua chave SSH pública</strong></h3><p>A seguir, você precisa copiar a sua chave SSH pública para a área de transferência.</p><p>Para Linux ou Mac, imprima o conteúdo da sua chave pública para o console com:</p><pre><code class="language-shell">cat ~/.ssh/id_rsa.pub # Linux</code></pre><p>Em seguida, selecione e copie o resultado.</p><p>Para o Windows, basta executar:</p><pre><code class="language-shell">clip &lt; ~/.ssh/id_rsa.pub # Windows</code></pre><h3 id="adicionar-a-sua-chave-ssh-p-blica-ao-github"><strong>Adicionar a sua chave SSH pública ao GitHub</strong></h3><p>Vá para a sua página de <a href="https://github.com/settings/keys">configurações</a> do GitHub e clique no botão "New SSH key":</p><p>Em seguida, dê à sua chave um título reconhecível e cole sua chave pública (id_rsa.pub):</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-15.png" class="kg-image" alt="image-15" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/image-15.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-15.png 656w" width="656" height="538" loading="lazy"></figure><p>Finalmente, teste a sua autenticação com:</p><pre><code class="language-shell">ssh -T git@github.com</code></pre><p>Se você seguiu todas estas etapas corretamente, você deve ver esta mensagem:</p><pre><code class="language-sh">Hi your_user_name! You've successfully authenticated, but GitHub does not provide shell access.
</code></pre><h3 id="mais-informa-es-sobre-o-ssh-textos-em-ingl-s-"><strong>Mais informações sobre o SSH (textos em inglês)</strong>:</h3><ul><li><a href="https://www.freecodecamp.org/news/the-ultimate-guide-to-ssh-setting-up-ssh-keys/">Ultimate guide to SSH</a></li><li><a href="https://www.freecodecamp.org/news/a-top-down-introduction-to-ssh-965f4fadd32e/">A top-down intro to SSH</a></li></ul> ]]>
                </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="800" height="396" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="450" 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="800" height="891" 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="727" height="250" 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="800" height="450" 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="800" height="536" 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="800" height="536" 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="800" height="548" 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 usar coleções em JavaScript – map e set ]]>
                </title>
                <description>
                    <![CDATA[ Em JavaScript, os objetos são usados para armazenar múltiplos valores como uma estrutura de dados complexa. Um objeto é criado com chaves {...} e uma lista de propriedades. Uma propriedade é um par de chave-valor, onde a chave deve ser uma string e o valor pode ser de qualquer tipo. ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-usar-colecoes-em-javascript-map-e-set/</link>
                <guid isPermaLink="false">635b94a6191d0905ea41a52f</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Thu, 15 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/cover-5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-use-javascript-collections-map-and-set/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use JavaScript Collections – Map and Set</a>
      </p><p>Em JavaScript, os objetos são usados para armazenar múltiplos valores como uma estrutura de dados complexa.</p><p>Um objeto é criado com chaves <code>{...}</code> e uma lista de propriedades. Uma propriedade é um par de chave-valor, onde a chave deve ser uma string e o valor pode ser de qualquer tipo.</p><p>Por outro lado, os arrays são uma coleção ordenada que pode conter dados de qualquer tipo. Em JavaScript, os arrays são criados com colchetes <code>[...]</code> e permitem a duplicação de elementos.</p><p>Até a ES6 (ECMAScript 2015), os objetos e arrays em JavaScript eram as estruturas de dados mais importantes para lidar com coleções de dados. A comunidade de desenvolvedores não tinha muitas opções além dessas duas. Mesmo assim, uma combinação de objetos e arrays era capaz de lidar com dados em muitos cenários.</p><p>No entanto, havia algumas falhas:</p><ul><li>As chaves dos objetos só podiam ser do tipo string.</li><li>Os objetos não mantinham a ordem dos elementos inseridos neles.</li><li>Os objetos carecem de alguns métodos úteis, o que os torna difíceis de usar em algumas situações. Por exemplo, não se pode calcular facilmente o tamanho (<code>length</code>) de um objeto. Além disso, a enumeração de um objeto não é tão direta.</li><li>Os arrays são coleções de elementos que permitem duplicatas. O suporte a arrays que tenham apenas elementos distintos requer lógica e código adicionais.</li></ul><p>Com a introdução do ES6, obtivemos duas novas estruturas de dados que abordam as falhas mencionadas acima: <code>Map</code> e <code>Set</code>. Neste artigo, analisaremos as duas estruturas de perto e entenderemos como utilizá-las em diferentes situações.</p><h2 id="map-em-javascript">Map em JavaScript</h2><p>O <code>map</code> é uma coleção de pares chave-valor onde a chave pode ser de qualquer tipo. O <code>map</code> lembra a ordem original em que os elementos foram adicionados a ele, o que significa que os dados podem ser recuperados na mesma ordem em que foram inseridos.</p><p>Em outras palavras, o <code>map</code> tem características tanto do objeto quanto do array:</p><ul><li>Como um objeto, ele suporta a estrutura de pares chave-valor.</li><li>Como um array, ele se lembra da ordem de inserção.</li></ul><h3 id="como-criar-e-inicializar-um-map-em-javascript"><strong>Como criar e inicializar um map em JavaScript</strong></h3><p>Um <code>map</code> pode ser criado assim:</p><pre><code class="language-js">const map = new Map();</code></pre><p>Isso retornará um <code>map</code> vazio:</p><pre><code class="language-shell">Map(0) {}</code></pre><p>Outro modo de criar um <code>map</code> é com valores iniciais. Veja como criar um <code>map</code> com três pares chave-valor:</p><pre><code class="language-js">const freeCodeCampBlog = new Map([
  ['nome', 'freeCodeCamp'],
  ['tipo', 'blog'],
  ['autor', 'Tapas Adhikary'],
]);</code></pre><p>Isso retornará um <code>map</code> com três elementos:</p><pre><code class="language-shell">Map(3) {"nome" =&gt; "freeCodeCamp", "tipo" =&gt; "blog", "autor" =&gt; "Tapas Adhikary"}</code></pre><h3 id="como-adicionar-valores-a-um-map-em-javascript">Como adicionar valores a um<strong> map em JavaScript</strong></h3><p>Para adicionar valor a um <code>map</code>, use o método set(chave, valor).</p><p>O método set(chave, valor) toma dois parâmetros, chave e valor, onde a chave e o valor podem ser de qualquer tipo, um primitivo (booleano, string, número etc.) ou um objeto:</p><pre><code class="language-js">// Cria um map
const map = new Map();

// Adiciona valores ao map
map.set('nome', 'freeCodeCamp');
map.set('tipo', 'blog');
map.set('autor', 'Tapas Adhikary');</code></pre><p>Resultado:</p><pre><code class="language-shell">Map(3) {"nome" =&gt; "freeCodeCamp", "tipo" =&gt; "blog", "autor" =&gt; "Tapas Adhikary"}</code></pre><p>Observe que, se você usar a mesma chave para adicionar um valor a um <code>map</code> várias vezes, ele sempre substituirá o valor anterior:</p><pre><code class="language-js">// Adicionar um escritor diferente
map.set('autor', 'Outra pessoa!');</code></pre><p>Assim, o resultado seria:</p><pre><code class="language-shell">Map(3) 
{"nome" =&gt; "freeCodeCamp", "tipo" =&gt; "blog", "autor" =&gt; "Outra pessoa!"}</code></pre><h3 id="como-obter-valores-de-um-map-em-javascript"><strong>Como obter valores de um map em JavaScript</strong></h3><p>Para obter um valor de um <code>map</code>, use o método get(chave):</p><pre><code class="language-js">map.get('nome'); // retorna freeCodeCamp</code></pre><h3 id="tudo-sobre-chaves-nos-maps-em-javascript"><strong>Tudo sobre chaves nos maps em JavaScript</strong></h3><p>As chaves em um <code>map</code> podem ser de qualquer tipo, um primitivo ou um objeto. Essa é uma das maiores diferenças entre o <code>map</code> e os objetos regulares em JavaScript, onde a chave só pode ser uma string:</p><pre><code class="language-js">// cria um Map
const funMap = new Map();

funMap.set(360, 'Número da minha casa'); // número como chave
funMap.set(true, 'Eu escrevo blogs!'); // booleano como chave

let obj = {'nome': 'tapas'}
funMap.set(obj, true); // objeto como chave

console.log(funMap);</code></pre><p>Aqui está o resultado:</p><pre><code class="language-shell">Map(3) 
{
  360 =&gt; "Número da minha casa", 
  true =&gt; "Eu escrevo blogs!", 
  {…} =&gt; true
}</code></pre><p>Um objeto regular do JavaScript sempre trata a chave como uma string. Mesmo quando você a passa como um primitivo ou objeto, ela converte internamente a chave em uma string:</p><pre><code class="language-js">// Cria um objeto vazio
const funObj = {};

// Adiciona uma propriedade. Nota, passando a chave como um número.
funObj[360] = 'My House Number';

// Retorna true porque o número 360 foi convertido na string '360' internamente!
console.log(funObj[360] === funObj['360']);</code></pre><h3 id="propriedades-de-map-e-m-todos-em-javascript"><strong>Propriedades de map e métodos em JavaScript</strong></h3><p>O map em JavaScript tem propriedades e métodos incorporados que o tornam fácil de usar. Aqui estão alguns dos métodos mais comuns:</p><ul><li>Use a propriedade <code>size</code> para saber quantos elementos estão em um <code>map</code>:</li><li>Busque um elemento com o método <code>has(chave)</code>:</li><li>Remova um elemento com o método <code>delete(chave)</code>:</li><li>Use o método <code>clear()</code> para remover todos os elementos do <code>map</code> de uma só vez:</li></ul><pre><code class="language-js">console.log('O tamanho do map é', map.size);</code></pre><pre><code class="language-js">// retorna true se o mapa tem um elemento com a chave "John".
console.log(map.has('John')); 


// retorna false se o map não tiver um elemento com a chave "Tapas".
console.log(map.has('Tapas')); </code></pre><pre><code class="language-js">map.delete('Sam'); // remove o elemento com chave "Sam".</code></pre><pre><code class="language-js">// limpa o map, removendo todos os elementos
map.clear(); 

map.size // retornará, 0
</code></pre><h3 id="o-mapiterator-keys-values-e-entries-em-javascript"><strong>O mapIterator: keys(), values() e entries() em JavaScript</strong></h3><p>Os métodos <code>keys()</code>, <code>values()</code> e <code>entries()</code> retornam um <code>MapIterator</code>, o que é excelente, pois você pode usar um laço <code>for-of</code> ou <code>forEach</code> diretamente sobre ele.</p><p>Primeiro, crie um <code>map</code>simples:</p><pre><code class="language-js">const ageMap = new Map([
  ['Jack', 20],
  ['Alan', 34],
  ['Bill', 10],
  ['Sam', 9]
]);</code></pre><ul><li>Obtenha todas as chaves:</li><li>Obtenha todos os valores:</li><li>Obtenha todas as entradas (pares chave-valor):</li></ul><pre><code class="language-js">console.log(ageMap.keys());

// Resultado:

// MapIterator {"Jack", "Alan", "Bill", "Sam"}</code></pre><pre><code class="language-js">console.log(ageMap.values());

// Resultado:

// MapIterator {20, 34, 10, 9}</code></pre><pre><code class="language-js">console.log(ageMap.entries());

// Resultado

// MapIterator {"Jack" =&gt; 20, "Alan" =&gt; 34, "Bill" =&gt; 10, "Sam" =&gt; 9}</code></pre><h3 id="como-iterar-sobre-um-map-em-javascript"><strong>Como iterar sobre um map em JavaScript</strong></h3><p>Você pode usar os laços <code>forEach</code> ou <code>for-of</code> para iterar sobre um <code>map</code>:</p><pre><code class="language-js">// com forEach
ageMap.forEach((value, key) =&gt; {
   console.log(`${key} tem ${value} anos de idade!`);
});

// com for-of
for(const [key, value] of ageMap) {
  console.log(`${key} tem ${value} anos de idade!`);
}</code></pre><p>O resultado será o mesmo em ambos os casos:</p><pre><code class="language-shell">Jack tem 20 anos de idade!
Alan tem 34 anos de idade!
Bill tem 10 anos de idade
Sam tem 9 anos de idade!</code></pre><h3 id="como-converter-um-objeto-em-um-map-em-javascript"><strong>Como converter um objeto em um map em JavaScript</strong></h3><p>Você pode encontrar uma situação na qual você precisa converter um objeto em uma estrutura semelhante a um <code>map</code>. Você pode usar o método de objeto <code>entries</code> para fazer isso:</p><pre><code class="language-js">const address = {
  'Tapas': 'Bangalore',
  'James': 'Huston',
  'Selva': 'Srilanka'
};

const addressMap = new Map(Object.entries(address));</code></pre><h3 id="como-converter-um-map-em-um-objeto-em-javascript"><strong>Como converter um map em um objeto em JavaScript</strong></h3><p>Se você quiser fazer o contrário, você pode usar o método <code>fromEntries</code>:</p><pre><code class="language-js">Object.fromEntries(map)</code></pre><h3 id="como-converter-um-map-em-um-array-em-javascript"><strong>Como converter um map em um array em JavaScript</strong></h3><p>Há algumas maneiras de converter um <code>map</code> em um array:</p><ul><li>Usando <code>Array.from(map)</code>:</li><li>Usando o operador spread:</li></ul><pre><code class="language-js">const map = new Map();
map.set('leite', 200);
map.set("chá", 300);
map.set('café', 500);

console.log(Array.from(map));</code></pre><pre><code class="language-js">console.log([...map]);</code></pre><h3 id="map-x-objeto-quando-voc-deve-us-los"><strong>Map x objeto: </strong>quando você deve usá-los?</h3><p>O <code>map</code> tem características tanto do objeto quanto do array. Entretanto, o <code>map</code> é mais como um objeto do que um array devido à natureza do armazenamento dos dados no formato chave-valor.</p><p>A similaridade com os objetos termina aqui. Como você já viu, o <code>map</code> é diferente em muitos aspectos. Então, qual você deve usar e quando? Como você decide?</p><p>Use <code>map</code> quando:</p><ul><li>As suas necessidades não são tão simples assim. Você pode querer criar chaves que não sejam strings. Armazenar um objeto como uma chave é uma abordagem muito poderosa. O <code>map</code> dá a você esse poder por padrão.</li><li>Você precisa de uma estrutura de dados onde os elementos possam ser solicitados. Os objetos regulares não mantêm a ordem de suas entradas.</li><li>Você está procurando flexibilidade sem depender de uma biblioteca externa como o lodash. Você pode acabar usando uma biblioteca como o lodash porque não encontrou métodos como has(), values(), delete() ou uma propriedade <code>size</code> com um objeto normal. O <code>map</code> facilita isso para você, fornecendo todos esses métodos por padrão.</li></ul><p>Use um objeto quando:</p><ul><li>Você não tem nenhuma das necessidades listadas acima.</li><li>Você depende de JSON.parse(), pois um <code>map</code> não pode ser analisado por ele.</li></ul><h2 id="set-em-javascript"><strong>Set em JavaScript</strong></h2><p>Um <code>set</code> é uma coleção de elementos únicos que podem ser de qualquer tipo. O <code>set</code> é também uma coleção ordenada de elementos, o que significa que os elementos serão recuperados na mesma ordem em que foram inseridos.</p><p>Um <code>set</code> em JavaScript se comporta do mesmo modo que um conjunto matemático.</p><h3 id="como-criar-e-inicializar-um-set-em-javascript"><strong>Como criar e inicializar um Set em JavaScript</strong></h3><p>Um novo <code>set</code> pode ser criado assim:</p><pre><code class="language-js">const set = new Set();
console.log(set);</code></pre><p>O resultado será um <code>set</code> vazio:</p><pre><code class="language-shell">Set(0) {}</code></pre><p>Veja aqui como criar um <code>set</code> com alguns valores iniciais:</p><pre><code class="language-js">const fruitSet = new Set(['🍉', '🍎', '🍈', '🍏']);
console.log(fruitSet);</code></pre><p>Resultado:</p><pre><code class="language-shell">Set(4) {"🍉", "🍎", "🍈", "🍏"}</code></pre><h3 id="propriedades-e-m-todos-dos-sets-em-javascript"><strong>Propriedades e métodos dos sets em JavaScript</strong></h3><p>O <code>set</code> tem métodos para adicionar um elemento a ele, excluir elementos dele, verificar se existe um elemento nele e limpá-lo completamente:</p><ul><li>Use a propriedade <code>size</code> para saber o tamanho do <code>set</code>. Ele retorna o número de elementos contidos nele:</li><li>Use o método <code>add(elemento)</code> para adicionar um elemento ao <code>set</code>:</li></ul><pre><code class="language-js">set.size</code></pre><pre><code class="language-js">// Cria um set - saladSet
const saladSet = new Set();

// Adiciona alguns vegetais a ele
saladSet.add('🍅'); // tomate
saladSet.add('🥑'); // abacate
saladSet.add('🥕'); // cenoura
saladSet.add('🥒'); // pepino

console.log(saladSet);


// Resultado

// Set(4) {"🍅", "🥑", "🥕", "🥒"}</code></pre><p>Eu amo tomates! Que tal adicionar mais um?</p><p>Oh, não! Eu não posso – o <code>set</code> é uma coleção de elementos <em>únicos</em>:</p><pre><code class="language-js">saladSet.add('🍅');
console.log(saladSet);</code></pre><p>O resultado é o mesmo de antes – nada foi adicionado ao saladSet.</p><ul><li>Use o método <code>has(elemento)</code> para procurar se temos uma cenoura (🥕) ou um brócolis (🥦) no <code>set</code>:</li><li>Use o método <code>delete(elemento)</code> para remover o abacate(🥑) do <code>set</code>:</li></ul><pre><code class="language-js">// A salada tem uma 🥕, então retorna true
console.log('A salada tem uma cenoura?', saladSet.has('🥕'));

// A salada não tem um 🥦, então retorna false
console.log('A salada tem brócolis?', saladSet.has('🥦'));</code></pre><pre><code class="language-js">saladSet.delete('🥑');
console.log('Eu não gosto de 🥑, remova da salada:', saladSet);</code></pre><p>Agora, nosso <code>set</code> de saladas é o seguinte:</p><pre><code class="language-shell">Set(3) {"🍅", "🥕", "🥒"}</code></pre><ul><li>Use o método <code>clear()</code> para remover todos os elementos do <code>set</code>:</li></ul><pre><code class="language-js">saladSet.clear();</code></pre><h3 id="como-iterar-sobre-um-set-em-javascript"><strong>Como iterar sobre um </strong><code>set</code> <strong>em JavaScript</strong></h3><p>O <code>set</code> tem um método chamado <code>values()</code> que retorna um <code>SetIterator</code> para obter todos os seus valores:</p><pre><code class="language-js">// Cria um Set
const houseNos = new Set([360, 567, 101]);

// Obtenha o SetIterator utilizando o método values()
console.log(houseNos.values());</code></pre><p>Resultado:</p><pre><code class="language-js">SetIterator {360, 567, 101}</code></pre><p>Podemos usar um laço <code>forEach</code> ou <code>for-of</code> sobre isso para recuperar os valores.</p><p>Curiosamente, o JavaScript tenta tornar o <code>set</code> compatível com o <code>map</code>. É por isso que encontramos nele dois métodos que vimos em <code>map</code>, <code>keys()</code> e <code>entries()</code>.</p><p>Como <code>set</code> não tem chaves, o método <code>SetIterator</code> retorna um <code>SetIterator</code> para recuperar os seus valores:</p><pre><code class="language-js">console.log(houseNos.keys());

// Resultado

// console.log(houseNos.keys());</code></pre><p>Com <code>map</code>, o método <code>entries()</code> retorna um iterador para recuperar pares chave-valor. Novamente, não há chaves em um <code>set</code>, então <code>entries()</code> retorna um <code>SetIterator</code> para recuperar pares valor-valor:</p><pre><code class="language-js">console.log(houseNos.entries());

// Resultado

// SetIterator {360 =&gt; 360, 567 =&gt; 567, 101 =&gt; 101}</code></pre><h3 id="como-enumerar-sobre-um-set-em-javascript"><strong>Como enumerar sobre um set em JavaScript</strong></h3><p>Podemos enumerar sobre um <code>set</code> usando os laços <code>forEach</code> e <code>for-of</code>:</p><pre><code class="language-js">// com forEach

houseNos.forEach((valor) =&gt; {
   console.log(valor);
});


// com for-of

for(const valor of houseNos) {
   console.log(valor);
 }</code></pre><p>O resultado de ambos é:</p><pre><code class="language-shell">360
567
101</code></pre><h3 id="sets-e-arrays-em-javascript"><strong>Sets e arrays em JavaScript</strong></h3><p>Um array, como um <code>set</code>, permite adicionar e remover elementos. O <code>set</code>, no entanto, é bem diferente e não se destina a substituir os arrays.</p><p>A maior diferença entre um array e um <code>set</code> é que os arrays permitem que você tenha elementos duplicados. Além disso, algumas das operações de <code>set</code>, como <code>delete()</code> são mais rápidas do que as do array, como <code>shift()</code> ou <code>splice()</code>.</p><p>Pense em <code>set</code> como uma extensão de um array regular, apenas com mais capacidades. A estrutura de dados do <code>set</code> não é uma substituição do array. Ambos podem resolver problemas interessantes.</p><h3 id="como-converter-um-set-em-um-array-em-javascript"><strong>Como converter um set em um array em JavaScript</strong></h3><p>A conversão de um set em um array é simples:</p><pre><code class="language-js">const arr = [...houseNos];
console.log(arr);</code></pre><h3 id="valores-nicos-de-um-array-utilizando-o-set-em-javascript"><strong>Valores únicos de um array utilizando o set em JavaScript</strong></h3><p>Criar um <code>set</code> é uma maneira realmente fácil de remover valores duplicados de um array:</p><pre><code class="language-js">// Cria um array mixedFruit com algumas frutas duplicadas
const mixedFruit = ['🍉', '🍎', '🍉', '🍈', '🍏', '🍎', '🍈'];

// Passa o array para criar um set de frutas únicas
const mixedFruitSet = new Set(mixedFruit);

console.log(mixedFruitSet);</code></pre><p>Resultado:</p><pre><code class="language-shell">Set(4) {"🍉", "🍎", "🍈", "🍏"}</code></pre><h3 id="set-e-objetos-em-javascript"><strong>Set e objetos em JavaScript</strong></h3><p>Um <code>set</code> pode ter elementos de qualquer tipo, até mesmo objetos:</p><pre><code class="language-js">// Cria um objeto pessoa
const person = {
   'name': 'Alex',
   'age': 32
 };

// Cria um set e adiciona o objeto a ele
const pSet = new Set();
pSet.add(person);
console.log(pSet);</code></pre><p>Resultado:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-113.png" class="kg-image" alt="image-113" width="563" height="182" loading="lazy"></figure><p>Não há surpresas aqui - o <code>set</code> contém um elemento que é um objeto.</p><p>Vamos mudar uma propriedade do objeto e adicioná-la ao <code>set</code> novamente:</p><pre><code class="language-js">// Muda o nome da pessoa
person.name = 'Bob';

// Adiciona o objeto pessoa ao set novamente
pSet.add(person);
console.log(pSet);</code></pre><p>Qual você acha que será a saída? Dois objetos pessoa ou apenas um?</p><p>Aqui está a saída:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-114.png" class="kg-image" alt="image-114" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/image-114.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-114.png 622w" width="622" height="184" loading="lazy"></figure><p>O <code>set</code> é uma coleção de elementos únicos. Ao mudar a propriedade do objeto, não mudamos o objeto em si. Portanto, o <code>set</code> não permitirá a duplicação de elementos.</p><p>O <code>set</code> é uma ótima estrutura de dados a ser usada para além dos arrays em JavaScript. No entanto, ele não tem uma grande vantagem sobre os arrays regulares.</p><p>Use <code>set</code> quando precisar manter um conjunto distinto de dados para realizar operações de conjuntos, como união, interseção, diferença e assim por diante.</p><h3 id="em-resumo"><strong>Em resumo</strong></h3><p>Aqui está um repositório no GitHub onde você pode encontrar todo o código-fonte usado neste artigo. Se você o achou útil, mostre o seu apoio dando uma estrela ao repositório: <a href="https://github.com/atapas/js-collections-map-set">https://github.com/atapas/js-collections-map-set</a></p><p>Você também pode gostar de alguns dos meus outros artigos (em inglês):</p><ul><li><a href="https://blog.greenroots.info/my-favorite-javascript-tips-and-tricks-ckd60i4cq011em8s16uobcelc">My Favorite JavaScript Tips and Tricks</a></li><li><a href="https://blog.greenroots.info/javascript-equality-comparison-with-and-objectis-ckdpt2ryk01vel9s186ft8cwl">JavaScript equality and similarity with ==, === and Object.is()</a></li></ul><p>Se este artigo foi útil, compartilhe-o para que outros também possam ler. Você pode entrar em contato com autor pelo Twitter (<a href="https://twitter.com/tapasadhikary">@tapasadhikary</a>), fazer seus comentários, ou segui-lo por lá.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Exemplos de código de link em botões no HTML – como fazer hiperlinks em HTML usando o atributo HREF nas tags ]]>
                </title>
                <description>
                    <![CDATA[ Neste artigo, vamos explorar três maneiras diferentes de se fazer um botão em HTML agir como um link. Estes são os métodos que vamos analisar:  1. Estilizar um link para parecer um botão  2. Usar os atributos action e formaction em um formulário  3. Usar o evento ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/exemplos-de-codigo-de-link-em-botoes-no-html-como-fazer-hiperlinks-em-html-usando-o-atributo-href-nas-tags/</link>
                <guid isPermaLink="false">635be7f07e77d305f28d76b3</guid>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Wed, 14 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/6049c377a7946308b76862f0.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/html-button-link-code-examples-how-to-make-html-hyperlinks-using-the-href-attribute-on-tags/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">HTML Button Link Code Examples – How to Make HTML Hyperlinks Using the HREF Attribute on Tags</a>
      </p><p>Neste artigo, vamos explorar três maneiras diferentes de se fazer um botão em HTML agir como um link.</p><p>Estes são os métodos que vamos analisar:</p><ol><li>Estilizar um link para parecer um botão</li><li>Usar os atributos <em>action</em> e <em>formaction</em> em um formulário</li><li>Usar o evento <em>onclick</em> do JavaScript</li></ol><p>Primeiro, porém, vamos dar uma olhada na abordagem errada.</p><h3 id="por-que-esta-abordagem-com-um-elemento-n-o-funciona"><strong>Por que esta abordagem com um elemento não funciona?</strong></h3><p>O trecho de código abaixo leva ao site do freeCodeCamp quando ele é clicado.</p><pre><code class="language-html">  &lt;a href="https://www.freecodecamp.org/"&gt;
    &lt;button&gt;freeCodeCamp&lt;/button&gt;
  &lt;/a&gt; </code></pre><p>No entanto, essa não é uma marcação válida em HTML.</p><blockquote><em>O elemento <a href="https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element">a</a> pode ser envolvido por parágrafos inteiros, listas, tabelas e assim por diante. É possível usar até mesmo seções inteiras, desde que não haja conteúdo interativo dentro delas (por exemplo, botões ou outros links). - Fonte: </em>Grupo de Trabalho de Tecnologia de Aplicação de Hipertexto Web</blockquote><p>Essa é considerada uma má prática, pois torna difícil entender a intenção do usuário.</p><p>Os links devem navegar o usuário para outra parte da página da web ou para um site da web externo. Os botões devem realizar uma ação específica como o envio de um formulário.</p><p>Quando você aninha um dentro do outro, isso torna confusa a ação que você quer realizar. É por isso que é melhor não aninhar um botão dentro de um elemento de âncora.</p><h3 id="como-estilizar-um-link-que-se-pare-a-com-um-bot-o-com-css"><strong>Como estilizar um link que se pareça com um botão com CSS</strong></h3><p>Esta primeira abordagem não utiliza, de fato, um botão. Podemos estilizar uma tag de âncora para que se pareça com um botão usando o CSS.</p><p>Este é o estilo padrão do HTML para um elemento de âncora.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/blue-anchor-tag.png" class="kg-image" alt="blue-anchor-tag" width="268" height="114" loading="lazy"></figure><p>Podemos adicionar uma classe ao elemento de âncora e depois usar esse seletor de classe para estilizar o elemento.</p><pre><code class="language-html">  &lt;a class="fcc-btn" href="https://www.freecodecamp.org/"&gt;freeCodeCamp&lt;/a&gt;  
</code></pre><p>Se você quiser que o link abra em uma nova página, pode adicionar o atributo target="_blank", assim:</p><pre><code class="language-html">  &lt;a target="_blank" class="fcc-btn" href="https://www.freecodecamp.org/"&gt;freeCodeCamp&lt;/a&gt;  
</code></pre><p>Então, podemos adicionar uma cor de fundo e mudar a cor da fonte, desse modo:</p><pre><code class="language-css">.fcc-btn {
  background-color: #199319;
  color: white;
}</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/background-and-white-text.png" class="kg-image" alt="background-and-white-text" width="218" height="68" loading="lazy"></figure><p>O próximo passo é adicionar algum preenchimento (em inglês, <em>padding</em>) ao redor do texto:</p><pre><code class="language-css">.fcc-btn {
  background-color: #199319;
  color: white;
  padding: 15px 25px;
}</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/adding-padding-1.png" class="kg-image" alt="adding-padding-1" width="338" height="134" loading="lazy"></figure><p>Finalmente, podemos usar a propriedade <em>text-decoration</em> para remover o sublinhado do texto:</p><pre><code class="language-css">.fcc-btn {
  background-color: #199319;
  color: white;
  padding: 15px 25px;
  text-decoration: none;
}</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/removing-underline.png" class="kg-image" alt="removing-underline" width="332" height="142" loading="lazy"></figure><p>Agora temos um elemento de âncora que se parece com um botão.</p><p>Também podemos tornar este "botão" um pouco mais interativo mudando a cor de fundo, dependendo do estado do link.</p><pre><code class="language-css">.fcc-btn:hover {
  background-color: #223094;
}</code></pre><figure class="kg-card kg-embed-card"><iframe id="cp_embed_XWNyGBR" src="https://codepen.io/jessica-wilkins/embed/preview/XWNyGBR?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=XWNyGBR" title="Demo Pen" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p>Poderíamos deixar o design mais intrincado, mas a ideia é apenas mostrar o básico de como estilizar um link para que se pareça um botão.</p><p>Você também poderia optar por usar uma biblioteca do CSS, como o <a href="https://getbootstrap.com/">Bootstrap</a>.</p><pre><code class="language-html">  &lt;a class="btn btn-primary" href="https://www.freecodecamp.org/"&gt;freeCodeCamp&lt;/a&gt;  
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/bootstrap-styles.png" class="kg-image" alt="bootstrap-styles" width="330" height="138" loading="lazy"></figure><p>Se o seu projeto já inclui o Bootstrap, você pode usar os estilos de botões incorporados. Eu, no entanto, não importaria o Bootstrap apenas para estilizar um link.</p><h3 id="quais-s-o-os-problemas-com-esta-abordagem"><strong>Quais são os problemas com esta abordagem?</strong></h3><p>Há algumas discussões sobre o fato de ser uma boa prática criar links estilizados como botões. Alguns argumentarão que os links devem sempre se parecer com links e que os botões devem sempre se parecer com botões.</p><p>No livro da web chamado <a href="https://resilientwebdesign.com/">Resilient Web Design</a>, Jeremy Keith afirma que</p><blockquote><em>Um material não deve ser usado como substituto para outro. Caso contrário, o resultado final será enganoso.</em></blockquote><p>Por que eu me dei ao trabalho de trazer à tona esse debate?</p><p>O meu objetivo não é fazer com que você escolha um lado do debate em vez do outro. Só quero que vocês estejam cientes dessa discussão em andamento.</p><h2 id="como-usar-os-atributos-action-e-formaction-para-fazer-um-bot-o-de-formul-rio"><strong>Como usar os atributos <em>action </em>e <em>formaction </em>para fazer um botão de formulário</strong></h2><h3 id="como-usar-o-atributo-action"><strong>Como usar o atributo <em>action</em></strong></h3><p>Outra alternativa seria aninhar o botão dentro de um formulário e usar o atributo <em>action</em>.</p><p>Exemplo de entrada:</p><pre><code class="language-html">  &lt;form action="https://www.freecodecamp.org/"&gt;
    &lt;input type="submit" value="freeCodeCamp"&gt;
  &lt;/form&gt;</code></pre><p>Exemplo de botão:</p><pre><code class="language-html">  &lt;form action="https://www.freecodecamp.org/"&gt;
    &lt;button type="submit"&gt;freeCodeCamp&lt;/button&gt;
  &lt;/form&gt;</code></pre><p>Este seria o estilo padrão do botão.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/default-button-style.png" class="kg-image" alt="default-button-style" width="300" height="104" loading="lazy"></figure><p>Poderíamos usar os mesmos estilos anteriores, mas teríamos que adicionar o ponteiro do cursor e definir o atributo <em>border</em> como <em>none</em>, assim:</p><pre><code class="language-css">.fcc-btn {
  background-color: #199319;
  color: white;
  padding: 15px 25px;
  text-decoration: none;
  cursor: pointer;
  border: none;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/removing-underline-1.png" class="kg-image" alt="removing-underline-1" width="332" height="142" loading="lazy"></figure><h3 id="como-utilizar-o-atributo-formaction"><strong>Como utilizar o atributo formaction</strong></h3><p>Similar à abordagem anterior, podemos criar um formulário e utilizar o atributo <em>formaction</em>.</p><p>Exemplo de entrada:</p><pre><code class="language-html">  &lt;form&gt;
    &lt;input type="submit" formaction="https://www.freecodecamp.org/" value="freeCodeCamp"&gt;
  &lt;/form&gt;</code></pre><p>Exemplo de botão:</p><pre><code class="language-html">  &lt;form&gt;
    &lt;button type="submit" formaction="https://www.freecodecamp.org/"&gt;freeCodeCamp&lt;/button&gt;
  &lt;/form&gt;</code></pre><p>Você só pode usar o atributo <em>formaction</em> com <em>input</em>s e <em>button</em>s que tenham os atributos <code>type="image"</code> ou <code>type="submit"</code>.</p><h3 id="isso-est-semanticamente-correto"><strong>Isso está semanticamente correto?</strong></h3><p>Embora essa pareça ser uma solução funcional, há uma questão a respeito de isso ser ou não semanticamente correto.</p><p>Estamos usando as tags de formulário, mas isso não funciona como um formulário real. O objetivo de um formulário é coletar e enviar dados do usuário.</p><p>Estamos, no entanto, usando o botão de envio para levar o usuário para outra página ou seção.</p><p>Quando se trata de semântica, essa não é uma boa prática de uso das tags de formulário.</p><h3 id="efeitos-colaterais-do-uso-dos-atributos-action-e-formaction"><strong>Efeitos colaterais do uso dos atributos <em>action </em>e <em>formaction</em></strong></h3><p>Quando você clica no botão, algo interessante acontece com o URL. O URL agora tem um ponto de interrogação ao final.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/question-mark-at-end.png" class="kg-image" alt="question-mark-at-end" width="300" height="64" loading="lazy"></figure><p>O motivo dessa mudança é porque o formulário está usando o método GET. Você poderia mudar para o método POST, mas pode haver casos onde isso também não seja o ideal.</p><pre><code class="language-html">  &lt;form method="POST" action="https://www.freecodecamp.org/"&gt;
    &lt;button type="submit"&gt;freeCodeCamp&lt;/button&gt;
  &lt;/form&gt;</code></pre><p>Embora essa abordagem produza uma marcação válida em HTML, ela vem com esse efeito colateral não intencional.</p><h2 id="como-usar-o-evento-onclick-do-javascript-para-fazer-um-bot-o"><strong>Como usar o evento <em>onclick </em>do JavaScript para fazer um botão</strong></h2><p>Nas abordagens anteriores, analisamos as soluções em HTML e em CSS. Também podemos usar o JavaScript para alcançar o mesmo resultado.</p><p>Exemplo de <em>input</em>:</p><pre><code class="language-html"> &lt;form&gt;
    &lt;input type="button" onclick="window.location.href='https://www.freecodecamp.org/';" value="freeCodeCamp" /&gt;
 &lt;/form&gt;</code></pre><p>Exemplo de <em>button</em>:</p><pre><code class="language-html">&lt;button onclick="window.location.href='https://www.freecodecamp.org/';"&gt;freeCodeCamp&lt;/button&gt;  
</code></pre><p><code>location.href</code> representa a localização de um URL específico. Nesse caso, o <code>window.location.href</code> retornará <a href="https://www.freecodecamp.org/">https://www.freecodecamp.org/</a>.</p><h3 id="desvantagens-dessa-abordagem"><strong>Desvantagens dessa abordagem</strong></h3><p>Embora essa solução funcione, há alguns problemas potenciais a serem considerados.</p><p>Se o usuário tiver decidido desativar o JavaScript em seu navegador, claramente, essa solução não funcionará. Infelizmente, isso poderá levar a uma má experiência para o usuário.</p><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>O objetivo deste artigo é mostrar três maneiras diferentes de se fazer botões agirem como links.</p><p>A primeira abordagem foi estilizar um link para que se parecesse com um botão. Também analisamos no debate se é uma boa ideia mudar a aparência dos links para se parecerem com outro elemento.</p><p>A segunda abordagem utilizou formulários e os atributos <em>action </em>e <em>formaction</em>. Também aprendemos, contudo, que essa abordagem tem alguns efeitos colaterais com o URL e não é semanticamente correta.</p><p>A terceira abordagem utilizou o evento <em>onclick </em>do JavaScript e <code>window.location.href</code>. Também aprendemos, porém, que essa abordagem pode não funcionar se o usuário decidir desativar o JavaScript em seu navegador.</p><p>Como desenvolvedor, é realmente importante observar os prós e os contras de uma abordagem específica antes de incorporá-la em seu projeto.</p><p>Espero que tenham gostado deste artigo e aprendido algumas coisas na leitura.</p><p>Desejo a você uma ótima programação! 😀</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Atributo "role" do HTML explicado ]]>
                </title>
                <description>
                    <![CDATA[ O atributo role (em português, "função" ou "papel") descreve a função de um elemento em programas que podem fazer uso dele, como leitores de tela ou lupas. Exemplo de uso: <a href="#" role="button">Link de botão</a> Os leitores de tela lerão esse elemento como um "botão" ao invés de um "link". ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/atributo-role-do-html-explicado/</link>
                <guid isPermaLink="false">635ccd5d7e77d305f28d7ca8</guid>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elizabete Nakamura ]]>
                </dc:creator>
                <pubDate>Tue, 13 Dec 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/5f9c9de7740569d1a4ca3a4b.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/html-role-attribute/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">HTML Role Attribute Explained</a>
      </p><p>O atributo <code>role</code> (em português, "função" ou "papel") descreve a função de um elemento em programas que podem fazer uso dele, como leitores de tela ou lupas.</p><p>Exemplo de uso:</p><pre><code class="language-html">&lt;a href="#" role="button"&gt;Link de botão&lt;/a&gt;</code></pre><p>Os leitores de tela lerão esse elemento como um "botão" ao invés de um "link".</p><p>Há quatro categorias de <em>roles</em>:</p><ul><li><em>Roles</em> abstratos</li><li><em>Roles</em> de widget </li><li><em>Roles</em> de estrutura de documento</li><li><em>Roles</em> de ponto de referência</li></ul><h2 id="mais-informa-es-sobre-os-atributos-do-html-textos-em-ingl-s-"><strong>Mais informações sobre os atributos do HTML (textos em inglês):</strong></h2><p><a href="https://guide.freecodecamp.org/html/attributes/script-src-attribute/">atributo &lt;script src&gt;</a></p><p><a href="https://guide.freecodecamp.org/html/attributes/a-href-attribute/">atributo &lt;a href&gt;</a></p><p><a href="https://guide.freecodecamp.org/html/attributes/a-target-attribute/">atributo &lt;a target&gt;</a></p><p><a href="https://guide.freecodecamp.org/html/attributes/body-background-attribute/">atributo &lt;body background&gt;</a></p><p><a href="https://guide.freecodecamp.org/html/attributes/p-align-attribute/">atributo &lt;p align&gt;</a></p><p><a href="https://guide.freecodecamp.org/html/attributes/img-src-attribute/">atributo &lt;img src&gt;</a></p><p><a href="https://guide.freecodecamp.org/html/attributes/font-color-attribute/">&lt;font&gt; attribute</a></p><h2 id="atributos-em-html"><strong>Atributos em HTML</strong></h2><p>Os elementos em HTML podem ter atributos, que contêm informações adicionais sobre o elemento.</p><p>Os atributos do HTML geralmente vêm em pares nome-valor. Eles sempre vão na tag de abertura de um elemento. O nome do atributo diz que tipo de informação você está fornecendo sobre o elemento e o valor dele é a informação real.</p><p>Por exemplo, um elemento âncora (&lt;a&gt;) em um documento em HTML cria links para outras páginas ou outras partes da página. Você usa o atributo <em>href</em> na tag de abertura de &lt;a&gt; para informar ao navegador para onde o link envia um usuário.</p><p>Aqui está um exemplo de um link que envia os usuários para a página inicial do freeCodeCamp:</p><pre><code class="language-html">&lt;a href="www.freecodecamp.org"&gt;Clique aqui para visitar o freeCodeCamp!&lt;/a&gt;</code></pre><p>Observe que o nome do atributo (<em>href</em>) e o valor ("<em>www.freeCodeCamp.org</em>") são separados com um sinal de igual. As aspas cercam o valor.</p><p>Existem muitos atributos diferentes em HTML, mas a maioria deles trabalha apenas com certos elementos do HTML. Por exemplo, o atributo <em>href </em>não funcionará se for colocado em uma tag &lt;h1&gt;.</p><p>No exemplo acima, o valor fornecido para o atributo <em>href </em>poderia ser qualquer link válido. Entretanto, alguns atributos têm apenas um conjunto de opções válidas que você pode usar, ou os valores precisam estar em um formato específico. O atributo <em>lang</em> diz ao navegador o idioma padrão do conteúdo em um elemento <em>&lt;html&gt;</em>. Os valores para o atributo <em>lang </em>devem usar o idioma padrão ou os códigos de país, como <em>en</em> para o inglês ou <em>it</em> para o italiano.</p><h2 id="atributos-booleanos"><strong>Atributos booleanos</strong></h2><p>Alguns atributos do HTML não precisam de um valor porque eles têm apenas uma opção. Eles são chamados de atributos booleanos. A presença do atributo em uma tag o aplicará a esse elemento do HTML. Entretanto, não há problema de escrever o nome do atributo e defini-lo como a única opção do valor. Neste caso, o valor é normalmente o mesmo que o atributo nome.</p><p>Por exemplo, o elemento &lt;input&gt; em um formulário pode ter um atributo <em>required </em>(em português, <em>obrigatório</em>). Isso exige que os usuários preencham esse item antes de poderem enviar um formulário.</p><p>Aqui estão exemplos de sintaxe que fazem a mesma coisa:</p><pre><code class="language-html">&lt;input type="text" required &gt;
&lt;input type="text" required="required" &gt;</code></pre> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
