<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Giovanny Cordeiro</title>
    <description>The latest articles on DEV Community by Giovanny Cordeiro (@giovannycordeiro).</description>
    <link>https://dev.to/giovannycordeiro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F995280%2Fd0d118c5-375b-4056-afa3-db3653fa3158.jpeg</url>
      <title>DEV Community: Giovanny Cordeiro</title>
      <link>https://dev.to/giovannycordeiro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/giovannycordeiro"/>
    <language>en</language>
    <item>
      <title>Multithreading e corrotinas com Ruby</title>
      <dc:creator>Giovanny Cordeiro</dc:creator>
      <pubDate>Sat, 07 Sep 2024 16:03:12 +0000</pubDate>
      <link>https://dev.to/giovannycordeiro/multithreading-e-corotinas-com-ruby-4hm5</link>
      <guid>https://dev.to/giovannycordeiro/multithreading-e-corotinas-com-ruby-4hm5</guid>
      <description>&lt;p&gt;O mecanismo de multithreading é o que permite ao desenvolvedor executar várias rotinas simultaneamente, promovendo um resultado mais rápido e eficiente em alguns cenários. Metaforicamente, seria como em uma loja: enquanto uma pessoa atende o cliente, outra está no estoque separando o pedido, outra oferecendo um café e assim por diante, todas colaborando para a melhor experiência do cliente. Agora, relacionando esse exemplo com a computação, a loja seria o programa multithread e as pessoas, as threads. Neste artigo, explico como utilizar os principais módulos de multithreading em Ruby, como &lt;code&gt;Threads&lt;/code&gt;, &lt;code&gt;Fibers&lt;/code&gt; e &lt;code&gt;Ractors&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tabela de conteúdos
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Como o Ruby lida com multithread&lt;/li&gt;
&lt;li&gt;Thread: O Principal modulo para multithread em Ruby&lt;/li&gt;
&lt;li&gt;Fibers: Utilizando corrotinas com Ruby&lt;/li&gt;
&lt;li&gt;Ractors: Como passar por cima do GIL&lt;/li&gt;
&lt;li&gt;Conclusão e agradecimentos&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Como o Ruby lida com multithread
&lt;/h1&gt;

&lt;p&gt;Antes de entrar de cabeça no entendimento dos módulos é necessário dar uma contextualização a respeito de como o Ruby lida por padrão com threads e como ele garante o &lt;a href="https://pt.stackoverflow.com/questions/76758/o-que-uma-classe-thread-safety-significa" rel="noopener noreferrer"&gt;thread safety&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O Ruby lida com Threads e garante o thread safety de suas aplicações por meio do &lt;a href="https://jonathan-wong.medium.com/what-is-global-interpreter-lock-in-relation-to-ruby-18d0f4f20e20" rel="noopener noreferrer"&gt;GIL (Global Interpreter Lock)&lt;/a&gt;, é o GIL que bloqueia que um programa Ruby tenha mais que uma thread, pois, com apenas uma thread executando, garantimos que não teremos nenhum dos problemas que multithreads podem acarretar, como &lt;em&gt;race condition&lt;/em&gt;, &lt;em&gt;deadlocks&lt;/em&gt;, &lt;em&gt;starvation&lt;/em&gt; e etc, caso deseje aprender a respeito desse o conteúdo, recomendo o ártigo &lt;a href="https://pradeesh-kumar.medium.com/deadlock-livelock-race-condition-and-starvation-c225018bbae6" rel="noopener noreferrer"&gt;Deadlock, Livelock, Race condition and Starvation&lt;/a&gt; para começar.&lt;/p&gt;

&lt;p&gt;A utilização do GIL é bastante frequente em linguagens de programação interpretadas. O Python, por exemplo, também tem um GIL e é isso que garante o Thread Safety.&lt;/p&gt;

&lt;p&gt;Com base nessa explicação, geralmente não é possível implementar multithread com Ruby, a menos que ignoremos o GIL ou Ruby nos forneça outra maneira de usar um código paralelo.&lt;/p&gt;

&lt;p&gt;E é por meio da utilização de outro artifício que a classe &lt;code&gt;Thread&lt;/code&gt; implementa multithread. Agora vamos entender como utilizar o modulo &lt;code&gt;Thread&lt;/code&gt; e como esse “outro artifício” funciona.&lt;/p&gt;

&lt;h1&gt;
  
  
  Thread: O Principal modulo para multithread em Ruby
&lt;/h1&gt;

&lt;p&gt;O principal módulo para realizar multithread em Ruby, como já mencionado, é o módulo &lt;code&gt;Thread&lt;/code&gt;. É dele que podemos criar e manipular threads no Ruby. Primeiramente vamos entender como criar uma Thread.&lt;/p&gt;

&lt;p&gt;Para criar uma Thread em Ruby, é necessário seguir algumas etapas bastante simples, vou apresentar um exemplo e logo em seguida vou explicar como o mesmo se comporta.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Uma mensagem que esta executando na thread'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Fim do programa'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Primeiramente, declaramos a nova Thread, instânciando a classe &lt;code&gt;Thread&lt;/code&gt; com o método &lt;code&gt;⁣.new&lt;/code&gt;. Em seguida, declaramos o código que desejamos que a Thread execute, que no nosso caso é a mensagem no terminal &lt;code&gt;Uma mensagem que está executando na thread&lt;/code&gt;⁣&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ao final do programa, mandamos uma mensagem com o texto "Fim de programa"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No entanto, caso executemos esse código, o resultado será a mensagem "Fim do programa", quando gostaríamos que fosse, "uma mensagem que está executando na thread" e, logo em seguida, a mensagem do "Fim do programa".&lt;/p&gt;

&lt;p&gt;Para entender esse erro no fluxo de execução, precisamos entender como a classe &lt;code&gt;Thread&lt;/code&gt; utiliza o “artificio” que mencionamos no começo do artigo e como isso impacta a execução do programa.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Artificio da classe Thread
&lt;/h2&gt;

&lt;p&gt;Para manter o Thread Safety garantido pelo GIL, o Ruby usa um mecanismo que, em resumo, "desvia" do GIL. Vamos entender isso mais de perto.&lt;/p&gt;

&lt;p&gt;Ao usar o método &lt;code&gt;.new&lt;/code&gt; que instância a classe, o que acontece por debaixo dos panos é que o Ruby passa a Thread recém criada para o scheduler. O scheduler agenda a execução da Thread para que ela seja executada assim que possível pelo Sistema Operacional. Quando essa ela for executada, o valor é retornado para a Thread principal, que é a Thread do GIL e do interpretador Ruby.&lt;/p&gt;

&lt;p&gt;Por meio dessa manobra, não conseguimos controlar exatamente quando a nova Thread será executada. Pois, quando ela é passada para o scheduler não temos mais poder algum sobre ela, apenas temos a garantia de que será executada assim que possível.&lt;/p&gt;

&lt;p&gt;Com isso, vamos ter o mecanismo semelhante ao multithreading, mas que é gerenciado diretamente pelo sistema operacional.&lt;/p&gt;

&lt;p&gt;Agora, para resolver o problema do fluxo de execução do nosso exemplo, é importante entender que, enquanto a nova thread está sendo criada e agendada, a thread principal continuará a ser executada normalmente.&lt;/p&gt;

&lt;p&gt;Mas no caso de a thread principal terminar, ela automaticamente encerrará todas as suas threads filhas, o que pode impedir que as threads filhas alcancem o resultado desejado.&lt;/p&gt;

&lt;p&gt;E é justamente isso que está acontecendo no nosso caso: o programa principal termina antes que a execução da(s) filha(s), seja porque o scheduler não encontrou um momento oportuno para agendar a thread, seja porque estávamos no meio da execução do código passados a ela.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolvendo o problema
&lt;/h2&gt;

&lt;p&gt;Para resolver esse problema, precisaríamos desenvolver um método que avise à thread principal para aguardar a conclusão da execução da thread filha (ou das threads filhas, caso haja mais de uma) antes de finalizar a principal.&lt;/p&gt;

&lt;p&gt;Felizmente, não é necessário implementar esse método manualmente, pois o Ruby já fornece o método &lt;code&gt;.join&lt;/code&gt;. Método esse serve exatamente para fazer com que a thread principal aguarde a conclusão de uma ou mais threads filhas antes de terminar a sua própria execução.&lt;/p&gt;

&lt;p&gt;Vamos corrigir o nosso exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Uma mensagem que está executando na thread'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Fim do programa'&lt;/span&gt;
&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;'Fim do programa'
'Uma mensagem que está executando na thread'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, temos o resultado desejado com ambas as mensagens exibidas no terminal. Note que a mensagem "Fim do programa" aparece antes da mensagem "Uma mensagem que está executando na thread". Caso você queira inverter a ordem, basta chamar o método &lt;code&gt;.join&lt;/code&gt; antes da linha &lt;code&gt;puts 'Fim do programa'&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uma aplicação mais próxima da realidade
&lt;/h2&gt;

&lt;p&gt;Vamos agora explorar um exemplo mais real, que mostra uma aplicação prática e poderosa do uso de multithreading, permitindo-nos também explorar outros conceitos.&lt;/p&gt;

&lt;p&gt;No seguinte exemplo, temos um programa em Ruby que tem como objetivo baixar 12 imagens de maneira rápida, utilizando as URIs dessas imagens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'net/http'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'uri'&lt;/span&gt;

&lt;span class="n"&gt;pictures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w[ &amp;lt;&amp;lt;lista_com_12_URIs_de_imagens&amp;gt;&amp;gt; ]&lt;/span&gt;
&lt;span class="n"&gt;parts_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pictures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;

&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parts_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;part_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;arr_url&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;arr_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;total_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;group_index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;image_index&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"pica-pau-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;total_index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg"&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTPSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'wb'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Falha no momento da requisição &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:join&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lógica central do algoritmo é a seguinte: temos uma lista de 12 URIs de imagens armazenadas na variável &lt;code&gt;pictures&lt;/code&gt;. Dividimos essa lista em 3 partes iguais, que são armazenadas na variável &lt;code&gt;parts_list&lt;/code&gt;. Em seguida, utilizamos o método &lt;code&gt;parts_list.each_with_index.map&lt;/code&gt; para criar uma thread para cada parte da lista.&lt;/p&gt;

&lt;p&gt;Cada thread criada percorre a parte correspondente da lista de URIs usando o método &lt;code&gt;arr_url.each_with_index&lt;/code&gt;. Para cada URI, a thread realiza uma requisição que baixa a imagem e a salva na máquina do usuário, desde que a resposta da requisição seja bem-sucedida (&lt;code&gt;if response.is_a?(Net::HTTPSuccess)&lt;/code&gt;). Caso contrário, uma mensagem de falha é exibida no terminal.&lt;/p&gt;

&lt;p&gt;No entanto, vamos alisar um ponto especifico do código, que é o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parts_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;part_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;arr_url&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;arr_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="c1"&gt;# logica restante&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que, ao criar uma thread para cada parte da lista, precisamos passar a variável como argumento para o construtor da classe &lt;code&gt;Thread&lt;/code&gt;. Isso é feito na linha &lt;code&gt;Thread.new(part_list) do |arr_url|&lt;/code&gt;, onde &lt;code&gt;part_list&lt;/code&gt; é passado como argumento. Para que em seguida, utilizemos a variável como parâmetro dentro da thread, como mostrado em &lt;code&gt;arr_url.each_with_index do |uri, image_index|&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Você pode se perguntar por que devemos fazer dessa forma, quando poderíamos usar a variável &lt;code&gt;part_list&lt;/code&gt; diretamente, sem passá-la como argumento para a &lt;code&gt;Thread&lt;/code&gt;, como mostrado no exemplo a seguir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parts_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;part_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;part_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="c1"&gt;# logica restante&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Existe uma razão bem plausível para isso, nós priorizamos a primeira abordagem que passa a variável para a &lt;code&gt;Thread&lt;/code&gt; como argumento, para garantir o Thread safety e o compartilhamento eficaz de variáveis entre as threads.&lt;/p&gt;

&lt;p&gt;Usar a variável &lt;code&gt;part_list&lt;/code&gt; diretamente, por meio do escopo global como exemplificado na segunda abordagem, poderia causar problemas de execução e dessincronia entre as threads. Por exemplo: Se a Thread 01 for criada e entrar em execução, e logo em seguida a  Thread 02 ser criada, a Thread 01 poderia modificar &lt;code&gt;part_list&lt;/code&gt; enquanto a Thread 02 ainda estaria lendo a variável. Isso pode levar a erros de sincronização e tornar a detecção e correção desses erros bastante complicada.&lt;/p&gt;

&lt;p&gt;Para evitar esse tipo de confusão, seguimos a primeira implementação, que faz uma cópia do valor que queremos utilizar para cada nova Thread. Dessa forma, cada uma delas trabalha com sua própria cópia da variável, evitando problemas entre threads e garantindo a sincronização.&lt;/p&gt;

&lt;p&gt;A ilustração a seguir apresenta a primeira implementação de maneira mais visual.&lt;/p&gt;

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

&lt;p&gt;Esse tipo de implementação utilizando Multithreading promove uma melhoria de desempenho muito significativa quando comparado com a abordagem tradicional mono thread.&lt;/p&gt;

&lt;p&gt;Confira no vídeo a seguir e observe a diferença de tempo entre um algoritmo executado com uma única thread tradicional e o mesmo algoritmo otimizado com multithreading.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OlwbhFMtkaQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Caso tenha curiosidade em ver a diferença de desempenho na sua máquina ou analisar o código, você pode ver ambas implementações &lt;a href="https://github.com/GiovannyCordeiro/artigo-tecnico-multithread/tree/main/incremental%20vs%20multi%20thread" rel="noopener noreferrer"&gt;disponíveis aqui&lt;/a&gt; no meu GitHub.&lt;/p&gt;

&lt;h1&gt;
  
  
  Fibers: Utilizando corrotinas com Ruby
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Fibers&lt;/strong&gt; é um mecanismo que torna possível interromper a execução de uma parte do código para executar outra. Esse tipo de funcionalidade é também conhecido como corrotinas &lt;em&gt;(or coroutines, if you prefer to speak English)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Quando a &lt;a href="https://stackoverflow.com/questions/6885937/whats-the-technical-definition-for-routine" rel="noopener noreferrer"&gt;rotina&lt;/a&gt; principal é interrompida, ela permite que uma rotina secundária seja executada, com a expectativa de que, em algum momento, a rotina secundária retorne o controle para a rotina principal.&lt;/p&gt;

&lt;p&gt;É essa característica que faz com que as Fibers sejam multitarefas cooperativas, permitindo que as tarefas colaborem para que, ao final do programa, o resultado esperado seja alcançado.&lt;/p&gt;

&lt;p&gt;Por isso, fibers &lt;strong&gt;não são uma ferramenta que recorre a multithreading&lt;/strong&gt;, mas sim uma ferramenta para a implementação de corrotinas, que pode tornar sua aplicação menos complexa e/ou mais flexível.&lt;/p&gt;

&lt;p&gt;Vamos entender os comandos principais da abstração Fiber:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Fiber.new&lt;/code&gt; é usado para criar uma nova Fiber. Com esse comando, você pode definir a lógica da Fiber por meio de um &lt;a href="https://dev.to/dnovais/closures-block-proc-e-lambda-ruby-18f7#block"&gt;bloco&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;example_fiber.resume&lt;/code&gt;: Utilizado para executar o código que esta dentro de uma fiber.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Fiber.yield&lt;/code&gt;: Utilizado para retornar o controle para a rotina principal.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos analisar como esses comandos são utilizados com o exemplo prático seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fiber_example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Fiber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Processando &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="no"&gt;Fiber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Ola'&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;fiber_example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo, criamos uma Fiber usando o comando &lt;code&gt;Fiber.new&lt;/code&gt; e a armazenamos na variável &lt;code&gt;fiber_example&lt;/code&gt;. Dentro da Fiber, definimos uma lógica simples: percorrer cada item do array armazenado na variável &lt;code&gt;data&lt;/code&gt;. A cada iteração do array, registramos a mensagem "Processando #{item}" e retornamos a execução para a rotina principal, que foi a que chamou a Fiber.&lt;/p&gt;

&lt;p&gt;Toda essa lógica está apenas presente dentro da variável &lt;code&gt;fiber_example&lt;/code&gt; e será executada somente quando a Fiber for chamada com &lt;code&gt;fiber_example.resume&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Em seguida, temos um loop que executa o mesmo código três vezes. Em cada iteração, o loop envia a mensagem "Olá" e chama a Fiber.&lt;/p&gt;

&lt;p&gt;O resultado após a execução do código é o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ola
Processando 1
Ola
Processando 2
Ola
Processando 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que está acontecendo no algoritmo é o seguinte: ele executa o loop &lt;code&gt;3.times&lt;/code&gt;, que imprime a mensagem "Olá" no terminal durante a primeira iteração. Em seguida, o código da Fiber é executado, percorrendo o primeiro item do array &lt;code&gt;data&lt;/code&gt; e registrando a mensagem "Processando 1" no terminal. Após essa iteração, a execução da Fiber é pausada e retorna ao loop &lt;code&gt;3.times&lt;/code&gt; na rotina principal. Esse processo se repete até que o loop &lt;code&gt;3.times&lt;/code&gt; termine.&lt;/p&gt;

&lt;p&gt;Você pode estar se perguntando sobre o &lt;code&gt;nil&lt;/code&gt; após o loop &lt;code&gt;each&lt;/code&gt;. O retorno de &lt;code&gt;nil&lt;/code&gt; é necessário para informar à Fiber que sua execução chegou ao fim. Neste caso, o &lt;code&gt;nil&lt;/code&gt; explícito não é necessário, pois o loop &lt;code&gt;.each&lt;/code&gt; já retorna &lt;code&gt;nil&lt;/code&gt; ao final de sua execução.&lt;/p&gt;

&lt;p&gt;Veja o video da execução do algoritmo:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/iRxp9m5x_G0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Caso você tenha interesse em ver outro exemplo de uso de Fibers, vou deixar disponível no &lt;a href="https://github.com/GiovannyCordeiro/artigo-tecnico-multithread/tree/main/other_example_fiber" rel="noopener noreferrer"&gt;meu GitHub&lt;/a&gt; um algoritmo de contagem de palavras implementado com Fibers. Exemplo esse que vi no livro &lt;a href="https://pragprog.com/titles/ruby5/programming-ruby-3-3-5th-edition/" rel="noopener noreferrer"&gt;"Programming Ruby - The Pragmatic Programmers' Guide"&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Ractors: Como passar por cima do GIL
&lt;/h1&gt;

&lt;p&gt;É por meio do modulo &lt;code&gt;Ractor&lt;/code&gt; que conseguimos realmente criar multithreads com Ruby. Pois cada Ractor mantém seu próprio GIL, o que pode melhorar o desempenho.&lt;/p&gt;

&lt;p&gt;Com ractors podemos compartilhar valores entre threads, mas apenas por maneiras pre-definidas.&lt;/p&gt;

&lt;p&gt;No livro "Programming Ruby - The Pragmatic Programmer's Guide", os autores explicam metaforicamente que um Ractor é como uma sala com uma porta de entrada e uma porta de saída, cada uma com possíveis filas.&lt;/p&gt;

&lt;p&gt;O conteúdo que preenche a sala representa o código que o Ractor executa, a porta de entrada é por onde os inputs chegam, e a porta de saída é por onde os outputs são gerados. É através dessas "portas" (metaforicamente falando) que o mecanismo de compartilhamento de variáveis funciona.&lt;/p&gt;

&lt;p&gt;Para compartilhar variáveis entre Ractors, ou seja, entre threads, você possui quatro opções:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Você pode enviar um valor diretamente para outro Ractor usando o método &lt;code&gt;.send&lt;/code&gt;, por exemplo, &lt;code&gt;other_ractor.send&lt;/code&gt;. Na metáfora proposta pelo livro, isso é como enviar uma pessoa para a porta de outro Ractor. Essa mecânica é &lt;a href="https://stackoverflow.com/questions/2824225/what-is-non-blocking-concurrency-and-how-is-it-different-than-normal-concurren" rel="noopener noreferrer"&gt;não bloqueante entre as threads&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Você pode receber o output de outro Ractor usando o método &lt;code&gt;other_ractor.take&lt;/code&gt;. Na metáfora, isso é como deixar uma pessoa na porta de saída do outro Ractor, com a tarefa de pegar o que sai da porta. No entanto, esse mecanismo é bloqueante, pois aguarda o resultado da outra thread.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dentro do código de um Ractor, você pode esperar receber um input externo para executar uma determinada ação. Metaforicamente, isso é como esperar alguém entrar pela porta de entrada. Isso pode ser feito usando o método &lt;code&gt;Ractor.receive&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Também dentro do código de um Ractor, você pode esperar que outro Ractor solicite um valor. Essa tarefa é bloqueante entre threads, pois o Ractor aguarda a solicitação de outro. É como esperar alguém bater na porta de saída para pedir algo, e então o Ractor reage, similar a um serviço de drive-thru.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Um conceito muito importante em Ractors é que todo novo Ractor criado é completamente isolado. Isso significa que o código dentro do Ractor só existe dentro dele e não pode acessar variáveis globais nem passar variáveis diretamente. A única forma de passar variáveis para um Ractor é por meio de chamadas ao método &lt;code&gt;.send&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Existem duas formas de chamadas a um Ractor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Chamadas externas: Mensagens enviadas para o Ractor a partir de outros lugares no código.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chamadas internas: Mensagens enviadas de dentro de uma classe que conhece a implementação específica do Ractor.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esses tipos de comunicação são de grande valia, porque permitem que você garanta o thread safety automaticamente, enviando valores entre Ractors por meio do método &lt;code&gt;.send&lt;/code&gt; e recebendo valores usando os métodos &lt;code&gt;.yield&lt;/code&gt; e &lt;code&gt;.take&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vamos ver um exemplo simples utilizando Ractors: um conversor paralelo de valores Celsius para Fahrenheit e Kelvin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;temperatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;ractor_fahrenheit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;celsius_list&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;celsius_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;9.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;ractor_kelvin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;celsius_list&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;celsius_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;273&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;list_fahrenheit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ractor_fahrenheit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;
&lt;span class="n"&gt;list_kelvin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ractor_kelvin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"List temperatures in Celsius: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;temperatures&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Converted temperatures in Fahrenheit: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;list_fahrenheit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Converted temperatures in Kevin: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;list_kelvin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo, o resultado no terminal seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List temperatures in Celsius: [0, 10, 20, 30, 40, 50]

Converted temperatures in Fahrenheit: [32.0, 50.0, 68.0, 86.0, 104.0, 122.0]

Converted temperatures in Kevin: [273, 283, 293, 303, 313, 323]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É importante deixar claro que o módulo Ractor ainda é experimental na versão Ruby 3.3.1, que foi a versão que utilizei para testar os códigos enquanto escrevia este artigo. Portanto, o módulo pode conter erros que ainda não foram corrigidos. Se optar por usá-lo, faça-o por sua própria conta e risco.&lt;/p&gt;

&lt;p&gt;Além disso, como Ractors realmente passam por cima do GIL e implementam multithreading real no Ruby, é crucial estar atento a problemas de sincronização de dados e deadlocks ao utilizar este módulo.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusão e agradecimentos
&lt;/h1&gt;

&lt;p&gt;Neste artigo, passamos pelos principais módulos de multithreading e corrotinas no Ruby: Threads, Fibers e Ractors. Enquanto estudava sobre esse tema, me surgiu várias ideias sobre como utilizá-los em diferentes cenários. Por isso, decidi escrever este artigo para compartilhar o conhecimento e ajudar outras pessoas a encontrarem outras formas de utilizar.&lt;/p&gt;

&lt;p&gt;Não poderia deixar de agradecer a &lt;a href="https://dev.to/cherryramatis"&gt;Cherry&lt;/a&gt;, o &lt;a href="https://twitter.com/henryhe4rt" rel="noopener noreferrer"&gt;Henry&lt;/a&gt; e o &lt;a href="https://dev.to/clintonrocha98"&gt;Clinton&lt;/a&gt; por ter disponibilizado um tempinho para ler esse artigo e propor melhorias e dicas, muito obrigado de verdade gente ❤️. Agradeço também a toda comunidade da &lt;a href="https://github.com/he4rt" rel="noopener noreferrer"&gt;He4rt Developers&lt;/a&gt; que sempre me ajuda quando passo por perrengues técnicos.&lt;/p&gt;

&lt;p&gt;Espero que o artigo tenha sido útil para entender os conceitos e as implementações desses módulos. Se você encontrar qualquer ponto negativo ou erro, estou totalmente à disposição para corrigir e aprender com você nos comentários!&lt;/p&gt;

&lt;h1&gt;
  
  
  Referências
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pragprog.com/titles/ruby5/programming-ruby-3-3-5th-edition/" rel="noopener noreferrer"&gt;Progamming Ruby - The pragmatic guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rubyguides.com/2015/07/ruby-threads/" rel="noopener noreferrer"&gt;How to Use Ruby Threads: An Easy To Understand Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>braziliandevs</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Memorização em Ruby</title>
      <dc:creator>Giovanny Cordeiro</dc:creator>
      <pubDate>Mon, 22 Jul 2024 20:58:39 +0000</pubDate>
      <link>https://dev.to/giovannycordeiro/memorizacao-em-ruby-5789</link>
      <guid>https://dev.to/giovannycordeiro/memorizacao-em-ruby-5789</guid>
      <description>&lt;p&gt;Gostar de desenvolver algoritmos que desempenham bem é uma característica presente na maioria dos devs, quando vemos aquele algoritmo bem escrito que performa lindamente sentimos aquela felicidade na alma, mas sabemos que muitas das técnicas de melhoria de desempenho envolvem muitos tradeofs e implementações complexas. Hoje eu vou explicar uma técnica bem simples para melhorar o desempenho dos seus algoritmos, &lt;strong&gt;a memorização&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;O que é memorização&lt;/li&gt;
&lt;li&gt;Primeira implementação utilizando operador de atribuição ou&lt;/li&gt;
&lt;li&gt;Segunda implementação utilizando a palavra chave defined&lt;/li&gt;
&lt;li&gt;Quando utilizar uma implementação ou outra&lt;/li&gt;
&lt;li&gt;Terceira implementação utilizando método tap&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  O que é memorização
&lt;/h1&gt;

&lt;p&gt;Em termos gerais, memorização é uma técnica que envolve você memorizar, lembrar ou guardar, de alguma forma, uma resposta de um método caro para evitar ficar usando desnecessariamente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O que seria um "método caro"? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um "método caro" seriam aqueles métodos que podem demandar muita memória, processamento, chamam diversos serviços terceiros ou que naturalmente têm uma complexidade inevitavelmente maior.&lt;/p&gt;

&lt;p&gt;Com essa definição em mente, o Ruby oferece ferramentas interessantes que permitem técnicas interessantes de implementação de memorização. Separei três técnicas que achei interessante para apresentar e vou explicá-las na seguinte ordem.&lt;/p&gt;

&lt;p&gt;Primeiramente, eu mostrarei as duas implementações principais de memorização, após isso, explicarei quando escolher uma ao invés da outra a depender do caso específico e por fim mostrarei uma terceira forma diferente de implementação a fim de conhecimento.&lt;/p&gt;

&lt;h1&gt;
  
  
  Primeira implementação utilizando operador de atribuição ou
&lt;/h1&gt;

&lt;p&gt;A primeira forma de implementar memorização é utilizando apenas o “operador de atribuição ou” &lt;code&gt;||=&lt;/code&gt;, sendo muito importante para o funcionamento adequado da memorização.&lt;/p&gt;

&lt;p&gt;Você pode estar se perguntando: “Certo, mas o que é esse abençoado 'operador de atribuição ou'?”&lt;/p&gt;

&lt;p&gt;Este operador segue apenas uma condição, só atribui um novo valor à variável se o valor atual for &lt;code&gt;false&lt;/code&gt; ou &lt;code&gt;nil&lt;/code&gt;. Caso contrário, ele irá manter o valor atual da variável.&lt;/p&gt;

&lt;p&gt;Vamos para um exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;example_variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="n"&gt;example_variavel&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="s1"&gt;'Giovanny'&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example_variable&lt;/span&gt; &lt;span class="c1"&gt;# 'Giovanny'&lt;/span&gt;

&lt;span class="n"&gt;example_variavel&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="s1"&gt;'Fulano'&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example_variable&lt;/span&gt; &lt;span class="c1"&gt;# 'Giovanny'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que na primeira atribuição do valor &lt;code&gt;Giovanny&lt;/code&gt; utilizando o “operador de atribuição ou” a variável &lt;code&gt;example_variable&lt;/code&gt; foi bem-sucedida, pois o valor atual da &lt;code&gt;example_variable&lt;/code&gt; era &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No entanto, na segunda atribuição, que tinha como valor &lt;code&gt;Fulano&lt;/code&gt; utilizando o “operador de atribuição ou” para a variável &lt;code&gt;example_variable&lt;/code&gt;, não foi bem-sucedida, pois o valor atual da variável &lt;code&gt;example_variable&lt;/code&gt; era uma &lt;code&gt;string&lt;/code&gt; “Giovanny” e não valores &lt;code&gt;nil&lt;/code&gt; ou &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Com isso em mente, podemos guardar o valor de retorno vindo de um método caro em uma variável utilizando o “operador de atribuição ou”. Uma vez que esse método for executado, a variável guardará esse valor e não será necessário executar o método novamente para o caso.&lt;/p&gt;

&lt;p&gt;No exemplo a seguir, o método caro será o &lt;code&gt;expensive_method&lt;/code&gt; e ele retornará como valor uma &lt;code&gt;string&lt;/code&gt;. Para deixar ainda mais claro, fixarei uma &lt;code&gt;string&lt;/code&gt; de retorno a fim de exemplificação, que nesse caso será a &lt;code&gt;string&lt;/code&gt; &lt;code&gt;MOLA&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EspecifiqClass&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_method&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="vi"&gt;@store&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;expensive_method&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kp"&gt;private&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expensive_method&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Executando expensive_method'&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="c1"&gt;# many logic&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="s1"&gt;'MOLA'&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EspecifiqClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt; &lt;span class="c1"&gt;# Retorno do valor "Mola" executando o expensive_method&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt; &lt;span class="c1"&gt;# Retorno do valor "Mola" sem executar o expensive_method&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;algorith_test git:(main) ✗ ruby test.rb
Executando expensive_method
MOLA
MOLA
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, percebe-se que estamos chamando duas vezes o método &lt;code&gt;some_method&lt;/code&gt;, no entanto, o método &lt;code&gt;some_method&lt;/code&gt; vai apenas chamar o método privado &lt;code&gt;expensive_method&lt;/code&gt; apenas na primeira vez.&lt;/p&gt;

&lt;p&gt;Isso faz sentido porque a variável &lt;code&gt;example&lt;/code&gt; é uma instância da classe &lt;code&gt;EspecifiqClass&lt;/code&gt; e, na primeira execução do método &lt;code&gt;some_method&lt;/code&gt; a variável &lt;code&gt;@store&lt;/code&gt; não tinha nenhum valor, logo, a condição do “operador de atribuição ou” vai ser atendida executando o método privado &lt;code&gt;expensive_method&lt;/code&gt; e armazenando seu resultado na variável &lt;code&gt;@store&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Já na segunda chamada do método &lt;code&gt;some_method&lt;/code&gt; a variável &lt;code&gt;@store&lt;/code&gt; agora tem um valor &lt;code&gt;MOLA&lt;/code&gt;, fazendo a condição do “operador de atribuição ou” não seja atendida e fazendo o método &lt;code&gt;some_method&lt;/code&gt; retorne o valor &lt;code&gt;MOLA&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Com isso, na segunda chamada, você acaba de ter o resultado esperado, mas sem demandar executar novamente o método caro. Podemos comprovar isso pela mensagem no console "Executando expensive_method" ser executada apenas uma vez.&lt;/p&gt;

&lt;h2&gt;
  
  
  E se...
&lt;/h2&gt;

&lt;p&gt;E se em vez o valor do retorno do método &lt;code&gt;expensive_method&lt;/code&gt; se uma &lt;code&gt;string&lt;/code&gt; estivéssemos recebendo um valor booleano (&lt;code&gt;true&lt;/code&gt; e &lt;code&gt;false&lt;/code&gt;), o que aconteceria?&lt;/p&gt;

&lt;p&gt;Aconteceria que teríamos o caso em que o valor &lt;code&gt;false&lt;/code&gt; seria efetivamente um valor a ser guardado na variável, mas como estamos utilizando diretamente o "operador de atribuição ou" (&lt;code&gt;||=&lt;/code&gt;) ele não iria guardar esse valor, pois, a condição do operador vai ser sempre positiva nesse caso, pois o valor vai ser efetivamente &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vamos mudar o método &lt;code&gt;expensive_method&lt;/code&gt; para que ele retorne um &lt;code&gt;boolean&lt;/code&gt;e vamos avaliar o seu funcionamento. Para facilitar a explicação, vamos fixar o valor &lt;code&gt;false&lt;/code&gt; como retorno.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EspecifiqClass&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_method&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="vi"&gt;@store&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;expensive_method&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kp"&gt;private&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expensive_method&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Executando expensive_method'&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="c1"&gt;# many logic&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EspecifiqClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;algorith_test git:(main) ✗ ruby test.rb
Executando expensive_method
false
Executando expensive_method
false
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos perceber que o &lt;code&gt;expensive_method&lt;/code&gt; está executando duas vezes mesmo quando efetivamente estamos devolvendo um valor &lt;code&gt;false&lt;/code&gt; que deveria ser guardado. Pelo motivo antes explicado da condição do "operador de atribuição ou" está sendo positiva ele não está guardando o valor &lt;code&gt;false&lt;/code&gt; e executando novamente o método &lt;code&gt;expensive_method&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nesse caso, temos valores falsos legítimos e precisamos consertar esse problema guardando o valor. Para suprir essa lacuna, a segunda implementação de memorização será bem útil.&lt;/p&gt;

&lt;h1&gt;
  
  
  Segunda implementação utilizando a palavra chave defined
&lt;/h1&gt;

&lt;p&gt;Para resolver o problema de “valores falsos legítimos” no caso do nosso método caro retornar valores falsos, precisamos verificar se existe um valor anterior na variável efetivamente.&lt;/p&gt;

&lt;p&gt;Caso exista algum valor, a gente retorna esse valor, caso contrário, a gente executa o método caro.&lt;/p&gt;

&lt;p&gt;Para verificar se a variável tem um valor ou não, podemos usar a palavra-chave &lt;a href="https://www.rubyguides.com/2018/10/defined-keyword/" rel="noopener noreferrer"&gt;&lt;code&gt;defined?&lt;/code&gt;&lt;/a&gt;. Essa palavra-chave verificará se a variável está definida ou não, caso esteja, ela retornará o tipo da declaração dela, caso não esteja, ela retornará &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Segue o exemplo desse conceito, na prática, utilizando o REPL do Ruby:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;001&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;defined?&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;002&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'test'&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;003&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;defined?&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"local-variable"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como podemos ver, quando verificamos se uma variável que não foi definida previamente está definida na primeira linha, ele retornará o valor &lt;code&gt;nil&lt;/code&gt;. Nesse caso, estamos verificando se a variável &lt;code&gt;example&lt;/code&gt; foi definida na primeira linha.&lt;/p&gt;

&lt;p&gt;Mas quando realmente definimos a variável na segunda linha e depois verificamos se ela foi definida na terceira linha o Ruby retorna o tipo de declaração dela.&lt;/p&gt;

&lt;p&gt;Agora, com esse entendimento da palavra-chave &lt;code&gt;defined?&lt;/code&gt; podemos realmente guardar valores &lt;code&gt;false&lt;/code&gt; legítimos da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EspecifiqClass&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_method&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="vi"&gt;@store&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;defined?&lt;/span&gt; &lt;span class="vi"&gt;@store&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="vi"&gt;@store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expensive_method&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expensive_method&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="c1"&gt;# many logic, return the boolean value&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EspecifiqClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt; &lt;span class="c1"&gt;# false (Executando o expensive_method)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some_method&lt;/span&gt; &lt;span class="c1"&gt;# false (Não executando o expensive_method)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na primeira linha do método &lt;code&gt;some_method&lt;/code&gt; ele verificará se a variável &lt;code&gt;@store&lt;/code&gt; foi definida, em caso positivo, ele retornará diretamente à variável com seu valor. Caso contrário, ele chamará o método &lt;code&gt;expensive_method&lt;/code&gt; que armazenará o valor retornado na variável &lt;code&gt;@store&lt;/code&gt; e retornará à variável.&lt;/p&gt;

&lt;h1&gt;
  
  
  Quando utilizar uma implementação ou outra
&lt;/h1&gt;

&lt;p&gt;Após mostrar as duas implementações, acredito que você já tenha uma boa noção de quando usar ambas, no entanto, eu vou apenas recapturar.&lt;/p&gt;

&lt;p&gt;Utilize a segunda implementação que usa a palavra-chave &lt;code&gt;defined?&lt;/code&gt; quando o método caro poder retornar um valor falso legitimo, com isso, você armazenará efetivamente o valor &lt;code&gt;false&lt;/code&gt; na variável normalmente.&lt;/p&gt;

&lt;p&gt;Caso o retorno da função cara seja de outros tipos como &lt;code&gt;strings&lt;/code&gt;ou &lt;code&gt;objects&lt;/code&gt;, por exemplo, você pode seguir a primeira implementação que utiliza apenas o “operador de atribuição ou” (&lt;code&gt;||=&lt;/code&gt;) normalmente, você estará tranquilo com essa implementação.&lt;/p&gt;

&lt;h1&gt;
  
  
  Terceira implementação utilizando método tap
&lt;/h1&gt;

&lt;p&gt;Existe uma terceira forma de fazer uma implementação de memorização onde o retorno do “método caro” é um hash no Ruby, que o engenheiro de software “Alex MacArthur” apresentou no seu artigo &lt;a href="https://macarthur.me/posts/memoization-with-tap-in-ruby/" rel="noopener noreferrer"&gt;"Elegant Memoization with Ruby’s .tap Method"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Inclusive, teve uma discussão interessante nesse artigo onde algumas pessoas alegam não enxergar efetivamente um “beneficio” na forma de implementação que o Sr. MacArthur trouxe. Caso tenha curiosidade sobre essa discussão &lt;em&gt;(como eu tive)&lt;/em&gt;, leia os comentários e os pontos que as pessoas trouxeram no artigo, não vou me atentar a detalhes aqui.&lt;/p&gt;

&lt;p&gt;De toda forma, achei interessante ver outra forma de implementação sobre o tema e por isso decidi mencionar aqui.&lt;/p&gt;

&lt;p&gt;Antes de ir para a implementação, é necessário entender o que é esse método &lt;code&gt;.tap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;De acordo com a &lt;a href="https://docs.ruby-lang.org/en/2.4.0/Object.html#method-i-tap" rel="noopener noreferrer"&gt;documentação do ruby&lt;/a&gt; em uma tradução direta, o método &lt;code&gt;.tap&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Entrega-se ao bloco e depois devolve-se. O objetivo principal deste método é “entrar” numa cadeia de métodos, de modo a realizar operações em resultados intermédios dentro da cadeia.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A documentação menciona a "cadeia" porque esse método brilha especialmente no debbug de cadeia de métodos, no entanto, vamos nos ater ao nosso tema.&lt;/p&gt;

&lt;p&gt;O que importa para nós é que ele apenas entra na cadeia e depois devolve normalmente, o que significa que podemos entrar em um hash e depois devolver resultados a ele&lt;/p&gt;

&lt;p&gt;Parece confuso, eu sei, mas vamos para um exemplo da implementação de memorização utilizando o método &lt;code&gt;.tap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nesse exemplo, temos uma classe chamada &lt;code&gt;ExampleClasse&lt;/code&gt; onde o método &lt;code&gt;people_detail&lt;/code&gt; vai memorizar detalhes das informações da pessoa, como nome e idade, mantendo o padrão do artigo, todos os dados também serão fixados no código.&lt;/p&gt;

&lt;p&gt;Segue o exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleClass&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="n"&gt;people_detail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;age&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="n"&gt;people_detail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'age'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kp"&gt;private&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;people_detail&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="vi"&gt;@people_detail&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="p"&gt;{}.&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;people_store&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Memorização people_detail'&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="n"&gt;people_store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Giovany'&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="n"&gt;people_store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'age'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;instance_one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ExampleClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;instance_one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;instance_one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado no console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Memorização people_detail
Giovany
20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nota-se que essa implementação é bem concisa em apenas um método, onde o próprio método verifica se a variável @people_detail é &lt;code&gt;false&lt;/code&gt; ou &lt;code&gt;nil&lt;/code&gt; com o “operador de atribuição ou” e em caso positivo, ele dispara o método &lt;code&gt;.tap&lt;/code&gt;que aplica a lógica que está sendo passada a ele que por sua vez armazena as informações no hash. Achei superinteressante essa outra forma de implementação.&lt;/p&gt;

&lt;p&gt;O resultado no console prova que a memorização dos dados foi feita de forma bem sucedida, pois a lógica passada para o método &lt;code&gt;.tap&lt;/code&gt; foi apenas executada uma vez, pelo que mostra a mensagem &lt;code&gt;Memorização people_detail&lt;/code&gt; no console.&lt;/p&gt;

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

&lt;p&gt;Existem mais formas de tornar mais complexo o tema, como, por exemplo, colocando mais parâmetros para memorizar, mas está fora do escopo desse artigo introdutor, talvez no futuro eu faça uma parte dois sobre esse tema. Espero que esse artigo tenha te ajudado a aprender sobre memorização!&lt;/p&gt;

&lt;p&gt;E claro, não poderia deixar de agradecer à &lt;a href="https://github.com/cherryramatisdev" rel="noopener noreferrer"&gt;Cherry&lt;/a&gt;, &lt;a href="https://github.com/Clintonrocha98" rel="noopener noreferrer"&gt;Cliton&lt;/a&gt; e ao &lt;a href="https://github.com/willfsouz" rel="noopener noreferrer"&gt;Williams&lt;/a&gt; por darem feedback nesse artigo antes dele ser postado, foi por conta deles que eu consegui deixar esse artigo melhor, meus sinceros muito obrigado ❤️.&lt;/p&gt;

&lt;h1&gt;
  
  
  Referências
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/baweaver/understanding-ruby-memoization-2be5"&gt;Understanding Ruby - Memoization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/t/ruby"&gt;Memoization in Ruby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://macarthur.me/posts/memoization-with-tap-in-ruby/" rel="noopener noreferrer"&gt;Elegant Memoization with Ruby’s .tap Method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/reactbrasil/o-poder-da-memoiza%C3%A7%C3%A3o-716fe0e6fd48" rel="noopener noreferrer"&gt;O poder da memoização&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.appsignal.com/2022/12/20/a-guide-to-memoization-in-ruby.html" rel="noopener noreferrer"&gt;A Guide to Memoization in Ruby&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>beginners</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Pequeno guia de webhooks com Ruby!</title>
      <dc:creator>Giovanny Cordeiro</dc:creator>
      <pubDate>Thu, 16 May 2024 10:50:02 +0000</pubDate>
      <link>https://dev.to/giovannycordeiro/pequeno-guia-de-webhooks-com-ruby-13mk</link>
      <guid>https://dev.to/giovannycordeiro/pequeno-guia-de-webhooks-com-ruby-13mk</guid>
      <description>&lt;p&gt;Nesse artigo irei explicar um pouco sobre Webhooks, seu uso e um exemplo prático ao final, espero que ajude seus estudos!&lt;/p&gt;

&lt;h2&gt;
  
  
  Inicio!
&lt;/h2&gt;

&lt;p&gt;O conceito formal fornecido pela &lt;a href="'https://www.redhat.com/pt-br/topics/automation/what-is-a-webhook'"&gt;RedHat&lt;/a&gt; é: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Um webhook é uma função de retorno de chamada baseada em HTTP que viabiliza a comunicação lightweight e orientada por eventos entre duas interfaces de programação de aplicações (APIs, na sigla em inglês)."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para sintetizar, um webhook existe para comunicar que um evento aconteceu em um sistema A para um sistema B.&lt;/p&gt;

&lt;p&gt;Se pararmos para pensar, esse conceito de "comunicar um evento que aconteceu em um sistema A para um sistema B" é muito útil, já que muitos sistemas precisam desse tipo de funcionalidade recorrentemente.&lt;/p&gt;

&lt;p&gt;Um exemplo legal e bem comum é um e-commerce, que depende de muitos sistemas diferentes se comunicando para funcionar adequadamente como sistema de pagamento, entrega, o marketplace, mecanismos de recomendações, etc. &lt;/p&gt;

&lt;p&gt;Para ficar mais fácil o exemplo que eu vou dar não irei mencionar muitas variáveis como essas no sistema, então, imagine então um sistema de e-commerce simples com apenas um serviço de pagamento.&lt;/p&gt;

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

&lt;p&gt;O e-commerce é naturalmente responsável por promover a venda e captar todas as informações necessárias do cliente, validar os dados, etc.&lt;/p&gt;

&lt;p&gt;Já o serviço de pagamento tem como objetivo de efetivamente comprovar o pagamento a respeito do pedido do cliente.&lt;/p&gt;

&lt;p&gt;É intuitivo pensar que você só poderá atualizar a página de feedback do pedido para "pagamento efetuado" depois que realmente o pagamento for efetuado, mas como a gente vai fazer para que o e-commerce saiba que o cliente efetivamente pagou o pedido?&lt;/p&gt;

&lt;p&gt;O serviço de pagamento é um sistema diferente do e-commerce, como a gente vai fazer para poder integrar ambos?&lt;/p&gt;

&lt;h2&gt;
  
  
  A primeira abordagem.
&lt;/h2&gt;

&lt;p&gt;A primeira e mais obvia solução é vc fazer uma função dentro do seu e-commerce que vai ficar fazendo requisições para o serviço de pagamento, perguntando se o cliente fez o pagamento daquele pedido, você não vai querer ficar disparando toda hora essa requisição e pode fazer com que ela faça a requisição de 1 em 1 minuto, parece OK certo?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ERRADO!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vamos supor que ocorreu o primeiro pedido do e-commerce e agora só falta o cliente realizar o pagamento, agora é só esperar ele pagar e dentro de 1 minuto sua aplicação vai atualizar a tela.&lt;/p&gt;

&lt;p&gt;No entanto... o usuário não paga depois desse 1 minuto e nem da o ar da graça nas próximas 2hrs, o que aconteceu foi que ele, enquanto fazia o pedido no e-commerce, esqueceu que tinha que levar a vó dele para o treino de Jiu Jitsu e como ele é um bom neto, vai ficar para prestigiar o treino de sua vó e vai demorar 2hrs para voltar. Mas o mesmo usuário pensou "vou deixar o pedido aqui, quando voltar eu pago".&lt;/p&gt;

&lt;p&gt;Nessas duas horas que se passaram seu e-commerce fez 120 requisições para o seu serviço se pagamento sem qualquer informação relevante do pagamento, sem qualquer nova atualização, perdendo capacidade computacional e gerando desperdício no sistema (Leia perca de dinheiro).&lt;/p&gt;

&lt;p&gt;E isso foi apenas de &lt;strong&gt;um&lt;/strong&gt; usuário imagina se fosse &lt;strong&gt;100&lt;/strong&gt; usuários, que é um numero baixo, seria &lt;strong&gt;12000&lt;/strong&gt; requisições jogadas completamente no lixo.&lt;/p&gt;

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

&lt;p&gt;E qual seria uma abordagem melhor?&lt;/p&gt;

&lt;h2&gt;
  
  
  Abordagem com Webhook
&lt;/h2&gt;

&lt;p&gt;Agora imagina que a gente pode ter um intermediário que avisa para o e-commerce que o pagamento de um pedido foi realizado? Isso seria ótimo certo? Iriamos fazer com que todo aquele desperdício da primeira abordagem fosse excluído e o sistema teria as informações atualizadas mais breve possível.&lt;/p&gt;

&lt;p&gt;E esse intermediário ótimo tem nome, ele se chama Webhook. Com o Webhook sendo orientado a evento, podemos avisar por meio dos serviço de pagamento que um determinado pedido foi pago para o e-commerce, de forma simples e fácil, a lógica é a seguinte:&lt;/p&gt;

&lt;p&gt;O serviço de pagamento avisa que foi pago um determinado pedido para o webhook, o webhook repassa essa informação para o e-commerce que atualiza agora a tela do usuário para "pagamento realizado" ou outra mensagem escolhida.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Fazendo o primeiro webhook simples!
&lt;/h2&gt;

&lt;p&gt;Vamos colocar a mão na massa e ver como realmente como implementar webhooks. Como eu já expliquei anteriormente webhooks servem para comunicar que um evento aconteceu em um sistema A para um Sistema B, para deixar mais enxuto, vou fazer APIs simples para do webhook.&lt;/p&gt;

&lt;p&gt;Para isso é necessário os seguintes elementos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primeira API: A primeira API fica esperando um evento acontecer na segunda, ligando com o exemplo que eu dei, poderia ser a API do e-commerce.&lt;/li&gt;
&lt;li&gt;O webhook &lt;/li&gt;
&lt;li&gt;Segunda API: Que acontece o evento e informa para o  webhook para a primeira API, ligando com o exemplo, seria o serviço de pagamento.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;As APIs nesse caso poderiam também ser um serviço ou outro sistema!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Só para deixar claro, os exemplos a seguir foram feitos em Ruby com o micro-framework Sinatra, pelo fato de ser a linguagem que eu estou mais gostando de estudar e aprender, mas você pode implementar o mesmo exemplo na sua ferramenta preferida.&lt;/p&gt;

&lt;p&gt;Também deixei todo os códigos em um repositório no Github para que você não precise ficar copiando, &lt;a href="https://github.com/GiovannyCordeiro/webhook" rel="noopener noreferrer"&gt;clicka aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Vamos começar criando a segunda API que é responsavel por notificar o evento para o webhook, o que ela precisa fazer é justamente fazer uma requisição simples para o webhook, como a gente faria para uma API normalmente. Segue o código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'sinatra'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rest-client'&lt;/span&gt;  
&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'test second app'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;    
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s1"&gt;'/service'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Logica do serviço de pagamento...     &lt;/span&gt;
    &lt;span class="n"&gt;data_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;'body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'dados para o primeiro serviço'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="no"&gt;RestClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s1"&gt;'http://127.0.0.1:4568/webhook/event-created'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;content_type: :json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;accept: :json&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos criar o próprio webhook, para isso você precisa criar outra API normalmente, no entanto, essa API vai receber os dados que vem da API 2 (no exemplo que dei, serviço de pagamento) e vai passar para a API 1 por meio de uma requisição POST (no exemplo que dei, e-commerce). Não atoa Webhook são chamados também como APIs inversas.&lt;/p&gt;

&lt;p&gt;Ou seja, o webhook recebe uma requisição de uma API (ou serviço) e faz outra requisição POST passando esses dados para outra API (ou serviço).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'sinatra'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rest-client'&lt;/span&gt;
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s1"&gt;'/webhook/event-created'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'chegou no webhook'&lt;/span&gt;
    &lt;span class="n"&gt;request_first_app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RestClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s1"&gt;'http://127.0.0.1:4567/recieve_event'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;headers: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Só ficou faltando criar a primeira API, que vai receber os dados da Segunda API por meio do webhook, fazendo assim com que tudo funcione da forma adequada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'sinatra'&lt;/span&gt;
&lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rewind&lt;/span&gt;
    &lt;span class="vi"&gt;@request_payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'hello world'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s1"&gt;'/recieve_event'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"evento que ocorreu no sistema 2, os dados são: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'body'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# logica após receber o dado do body....&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora o que vai acontecer? Quando você fizer uma requisição POST na rota &lt;code&gt;/service&lt;/code&gt; da segunda API essa ela mesma vai executar sua logica e avisar para o webhook que determinado evento evento ocorreu passando os dados escolhidos, o webhook repassa para a primeira API.&lt;/p&gt;

&lt;p&gt;Antes de testar, se atente em rodar as APIs e o Webhook nas portas certas, caso contrario, pode ser que tenha dor de cabeça com isso, logo as portas nesse meu exemplo são as seguintes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;first_app&lt;/em&gt;: porta 4567&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;weebhook&lt;/em&gt;: porta 4568&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;second_app&lt;/em&gt;: porta 4569&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Após rodar todas as aplicações com: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ruby src/nome_do_servico -p numero_da_porta&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Faça uma requisição POST com body JSON para o endpoint &lt;em&gt;&lt;a href="http://127.0.0.1:4569/service" rel="noopener noreferrer"&gt;http://127.0.0.1:4569/service&lt;/a&gt;&lt;/em&gt;, você notará que o dado mockado que você mandou no &lt;code&gt;second_app&lt;/code&gt; vai ser logado da mesma forma no &lt;code&gt;first_app&lt;/code&gt;, o que prova que conseguimos implementar de forma bem-sucedida o webhook.&lt;/p&gt;

&lt;h2&gt;
  
  
  É isso!
&lt;/h2&gt;

&lt;p&gt;Espero que esse artigo tenha te ajudado a entender sobre webhooks! Qualquer coisa estou a disposição de ajudar e trocar uma ideia sobre tech nas minhas redes sociais, é isso!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>14 Produtores de conteúdo da área de desenvolvimento de software.</title>
      <dc:creator>Giovanny Cordeiro</dc:creator>
      <pubDate>Mon, 15 Jan 2024 20:54:53 +0000</pubDate>
      <link>https://dev.to/giovannycordeiro/14-produtores-de-conteudo-da-area-de-desenvolvimento-de-software-29ko</link>
      <guid>https://dev.to/giovannycordeiro/14-produtores-de-conteudo-da-area-de-desenvolvimento-de-software-29ko</guid>
      <description>&lt;p&gt;Produtores de conteúdos são de suma importância para todas as áreas, isso é fato. Muitas vezes são eles que apresentam novos conteúdos, dão aquele empurrãozinho para você tirar aquele projeto que tanto queria do papel ou faz você começar a desenvolver aquela virtude que tanto queria a um tempo.&lt;/p&gt;

&lt;p&gt;Na área de tecnologia não é diferente, existe muitos produtores de conteúdo e com eles é possível ficar atualizado de vários segmentos e/ou temas, nesse artigo, eu vou vou listar &lt;strong&gt;14 produtores(as)&lt;/strong&gt; de conteúdo de tecnologia que mais me encheram os olhos nos últimos tempos.&lt;/p&gt;

&lt;p&gt;Já passa essa lista para aquele amigo/conhecido que começou na área que para ele melhore o aprendizado e fique por dentro das novidades.&lt;/p&gt;

&lt;p&gt;E para melhorar, todos dessa lista são brasileiros! &lt;/p&gt;

&lt;h2&gt;
  
  
  TL; DR;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Caso de você queira apenas a lista dos canais PT-BR.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/@filipedeschamps" rel="noopener noreferrer"&gt;Filipe Deschamps&lt;/a&gt;, &lt;a href="https://www.youtube.com/@attekitadev" rel="noopener noreferrer"&gt;Atekita Dev&lt;/a&gt;, &lt;a href="https://www.youtube.com/@loianegroner" rel="noopener noreferrer"&gt;Loiane Groner&lt;/a&gt;, &lt;a href="https://www.youtube.com/@GlauciaLemos" rel="noopener noreferrer"&gt;Glaucia Lemos&lt;/a&gt;, &lt;a href="https://www.youtube.com/@LucasMontano" rel="noopener noreferrer"&gt;Lucas Montano&lt;/a&gt;, &lt;a href="https://www.youtube.com/@LinuxTips" rel="noopener noreferrer"&gt;LINUXTips&lt;/a&gt;, &lt;a href="https://www.youtube.com/@codigofontetv" rel="noopener noreferrer"&gt;Codigo fonte TV&lt;/a&gt;, &lt;a href="https://www.youtube.com/@Akitando" rel="noopener noreferrer"&gt;Fabio Akita&lt;/a&gt;, &lt;a href="https://www.youtube.com/@manodeyvin" rel="noopener noreferrer"&gt;Mano Deyvin&lt;/a&gt;, &lt;a href="https://www.youtube.com/@kipperdev" rel="noopener noreferrer"&gt;Fernanda Kipper&lt;/a&gt;, &lt;a href="https://www.youtube.com/@ErickWendelTraining" rel="noopener noreferrer"&gt;Erick Wendel&lt;/a&gt;, &lt;a href="https://www.youtube.com/@Dunossauro" rel="noopener noreferrer"&gt;Eduardo Mendes&lt;/a&gt;, &lt;a href="https://www.youtube.com/@DevSoutinho" rel="noopener noreferrer"&gt;Mario Solto&lt;/a&gt;, &lt;a href="https://www.youtube.com/@GabsFerreira" rel="noopener noreferrer"&gt;Gabs Ferreira&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filipe Deschamps - Canal: &lt;a href="https://www.youtube.com/@filipedeschamps" rel="noopener noreferrer"&gt;Filipe Deschamps&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Também chamado de Michel Teló da computação, Filipe Deschamps tem um estilo cativante e uma oratoria calma. O que mais chama atenção no canal dele é que ele aborda diversos assuntos que fogem até do escopo de tecnologia de uma forma clara e sucinta trazendo paralelos (ou não) com a área de tecnologia, a sensação que tenho ao terminar de assistir algum um vídeo dele é geralmente de, "puts mas já acabou?", sentimento esse que me faz ansioso esperando seu próximo vídeo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Karol Attekita - Canal: &lt;a href="https://www.youtube.com/@attekitadev" rel="noopener noreferrer"&gt;Attekita Dev&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Karol Attekita foi uma grata surpresa desde que a conheci, com seu canal muito versátil ela explica desde conceitos simples até conteúdos mais técnicos mostrando mais o segmento em que trabalha (Nativo em IOs). Ela alimenta seu canal de forma recorrente e aborda os mais diversos temas relacionados a tecnologia, como dicas de carreira, soft, hard skills, tendências, etc. Além do mais ela tem experiência apenas como desenvolvedora Senior IOS na &lt;strong&gt;RIOT GAMES&lt;/strong&gt;, a mulher é simplesmente braba.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loiane Groner - Canal: &lt;a href="https://www.youtube.com/@loianegroner" rel="noopener noreferrer"&gt;Loiane Groner&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Se tu não conhece essa mulher tu ta perdendo muito, mas eu vou te tirar dessa escuridão, ela é simplesmente a autora do Livro "Estrutura de dados e algoritmos em JavaScript" que é &lt;strong&gt;apenas&lt;/strong&gt; umas das principais referencias para começar os estudos de estruturas de dados para iniciantes. Saber que ela é brasileira e saber que ela produz conteúdo em PT-BR é para mim simplesmente sensacional. No canal dela ela aborda majoritariamente conteúdos técnicos em Java e Angular, tecnologias que ela domina a provavelmente mais tempo do que eu tenho de vida, quer aprender mais sobre Angula, Java? Canal da Loiane.&lt;/p&gt;

&lt;h2&gt;
  
  
  Glaucia Lemos - Canal: &lt;a href="https://www.youtube.com/@GlauciaLemos" rel="noopener noreferrer"&gt;Glaucia Lemos&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Glaucia Lemos é outra mulher absurda da nossa lista, ela é atualmente Developer Advocate II na &lt;strong&gt;Microsoft&lt;/strong&gt; e tem muito conteúdo técnico em seu canal sobre Typescript e Azure, não somente isso, como também ela tema diversas entrevistas sobre outras tecnologias com outras pessoas extremamente qualificadas em seu canal, se você quer um canal brabo sobre Typescript e Azure, que tem um curso de typescript que da um pau em muito pago ai, o canal dela é o lugar. Não posso esquecer de mencionar que ela simplesmente tem uma carreira brilhante, com contribuição na Node.js Foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lucas Montano - Canal: &lt;a href="https://www.youtube.com/@LucasMontano" rel="noopener noreferrer"&gt;Lucas Montano&lt;/a&gt;.
&lt;/h2&gt;

&lt;p&gt;Lucas Montano do canal Lucas Montano é outro cara insano da área de desenvolvimento de software, ele é atualmente trabalha como Senior Android Engineer na Disney e aborda em seu canal diversos temas relacionados a tecnologia colocando seu ponto de vista baseado em sua experiência. Ele vai desde carreira, tecnologias, mercado, tendências, e até (porque não?) tretas. O que mais me atrai em assistir os vídeos do Montano é a sua personalidade e forma do qual guia os vídeos, que é sempre de uma forma espontânea e singular.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vanessa Weber e Gabriel Fróes - Canal: &lt;a href="https://www.youtube.com/@codigofontetv" rel="noopener noreferrer"&gt;Código Fonte TV&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Vanessa Weber e Gabriel Fróes são um casal de programadores que tem um canal de tecnologia muito relevante, além de serem empreendedores na área e tecnologia com a empresa RW Studio. &lt;/p&gt;

&lt;p&gt;O canal deles é recheado de quadros um melhores que os outros e que são feitos claramente com muita dedicação, dentre esses quadros eu particularmente gosto muito do "Compilado do código fonte TV", onde eles fazem um resumão das noticias de tecnologia da semana. No canal desse casal o que não falta é conteúdo, carisma e proficiência.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fábio Akita - Canal: &lt;a href="https://www.youtube.com/@Akitando" rel="noopener noreferrer"&gt;Akitando&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Fábio Akita é desenvolvedor de software com muitos anos de experiência e Co-Founder da Codeminers 42, empresa que é "uma boutique de software", como eles mesmos dizem.&lt;/p&gt;

&lt;p&gt;Se você estiver querendo aprender sobre desenvolvimento de software e tecnologia de forma HARDCORE, definitivamente é o seu lugar, o Akita produz conteúdos densos, objetivos, com comentários ácidos e opiniões fortes.&lt;/p&gt;

&lt;p&gt;Geralmente seus vídeos tem uma média de tempo de 1hr ou mais, por ai você consegue imaginar o tanto de informação e conteúdo que esse cara tem para te dizer.&lt;/p&gt;

&lt;p&gt;Quando assisto ou reassisto algum vídeo do Akita eu sempre tenho uma avalanche de informações e detalhes técnicos que muitas vezes eu não fazia ideia que existia ou deixei passar, definitivamente um canal para aprender de forma sólida conteúdos que não são tão "main stream", mas que são de suma importância na área de tecnologia. &lt;/p&gt;

&lt;h2&gt;
  
  
  Fernanda Kipper - Canal: &lt;a href="https://www.youtube.com/@kipperdev" rel="noopener noreferrer"&gt;kipperdev&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Fernanda Kipper é atualmente desenvolvedora de software Pleno na Itaú tem um canal no Youtube onde ela aborda diversos temas relacionados a tecnologia, como tendências, lifestyle, desafios, dentre outros. O que me chama atenção no canal dela além de sua oratória é a forma do qual ela é direta em relação a passar a ideia do vídeo, acho os vídeos dela sucintos, claros e bem fluidos. Focada em Java e Spring é outro canal muito bom para quem quer saber mais sobre essas tecnologias.&lt;/p&gt;

&lt;h2&gt;
  
  
  Erick Wendel - Canal: &lt;a href="https://www.youtube.com/@ErickWendelTraining" rel="noopener noreferrer"&gt;Erick Wendel&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Erick Wendel é desenvolvedor de software Senior, Linkedin Top Voice, Google Dev Expert, Microsoft MVP, Github Star, Node.JS &lt;strong&gt;core team member&lt;/strong&gt; e outras porradas de coisas.&lt;/p&gt;

&lt;p&gt;Além de todos esses títulos Erick foi o dev que corrigiu o bug no Node.Js (runtime do Javascript) que afetava o Facebook Jest, nem vou me arriscar explicando o que ele fez, até porque ele fez um vídeo onde explica de forma bem detalhada como corrigiu esse bug.&lt;/p&gt;

&lt;p&gt;Em seu canal Erick aborda sobre diversos temas de desenvolvimento de software, mas se você quiser um lugar para aprender mais sobre Node.js, para mim, o canal dele é um dos melhores. &lt;/p&gt;

&lt;h2&gt;
  
  
  Eduardo Mendes - Canal: &lt;a href="https://www.youtube.com/@Dunossauro" rel="noopener noreferrer"&gt;Eduardo Mendes&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Eduardo Mendes é desenvolvedor de software e seu canal é majoritariamente focado em conteúdos relacionados a Python. O que mais me surpreende no canal dele é a facilidade e didática que o Eduardo tem em relação a passar conteúdos mais técnicos, suas lives são ótimas e muito informativas. Caso você queira um canal para aprender mais sobre Python, o canal do Eduardo é um dos lugares para isso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mario Souto - Canal: Mario Souto - Dev Soutinho
&lt;/h2&gt;

&lt;p&gt;Mario Souto é Github Stars, Google Developer Expert e atualmente Lead Software Enginner na Nubank. Seu canal no youtube aborda diversos temas sobre tecnologia onde ele discute, explica e por muitas vezes implementa algo relacionado ao tópico.&lt;/p&gt;

&lt;p&gt;O que mais se destaca para mim no canal do Soutinho é o jeito alegre, espontâneo e (quando é necessário) sério, que ele aborda os temas, seja eles mais simples ou um pouco mais complexos, da para perceber a dedicação empregada no seu canal, acho isso sensacional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jeferson Fernando Vitalino - Canal: &lt;a href="https://www.youtube.com/@LinuxTips" rel="noopener noreferrer"&gt;LINUXtips&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Jeferson Fernando é Senior Platform Engenier e tem um dos canais mais influentes que eu conheço quando se trata de DevOps.&lt;/p&gt;

&lt;p&gt;O canal da Linux Tips é definitivamente um dos canais que mais tem conteúdo técnico sobre esse assunto, mas seu canal não é apenas focado nesse nicho. Ele também faz muitos eventos online onde há diversas palestras sobre diversas tecnologias e metodologias diferentes, o que eu mais gosto no canal Linux Tips é isso, conteúdo, muito conteúdo.&lt;/p&gt;

&lt;p&gt;Confesso que atualmente um dos meus quadros preferidos do canal é o "Falando e andando" onde ele fala sobre algum tema relacionado a tecnologia e vai caminhando em Amsterdam, cidade no qual ele vive atualmente. &lt;/p&gt;

&lt;h2&gt;
  
  
  Gabs Ferreira - Canal: &lt;a href="https://www.youtube.com/@GabsFerreira" rel="noopener noreferrer"&gt;Gabs ferreira&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Gabs é produtor de conteúdo em tempo integral atualmente, mas por muitos anos trabalhou na área de tecnologia e suas ultimas experiências foram como Developer Advocate.&lt;/p&gt;

&lt;p&gt;Seu canal do youtube é basicamente uma versão com vídeo do seu podcast "Olá Gabs" que foi uma grata surpresa para mim esse ano. Ele conduz o seu podcast de forma sensacional, com papos reflexivos, produtivos e memoráveis.&lt;/p&gt;

&lt;p&gt;Se você gosta de podcast e me pedisse uma lista de podcasts de desenvolvimento de software certamente o "Olá Gabs" estaria nessa lista.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mano Deyvin - Canal: &lt;a href="https://www.youtube.com/@manodeyvin" rel="noopener noreferrer"&gt;Mano Deyvin&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Many Devyn é Senior Software Engenier atualmente e com seu canal do youtube comenta de forma despojada e caótica temas relacionados a tecnologia. O conteúdo do Mano Deyvin me lembra muito lives da Twitch onde o conteúdo é bem doido, com um chat maluco e comentários zueiros, no entanto, repleto de informações valiosas para olhares atentos.&lt;/p&gt;

&lt;p&gt;Eu recomendo o canal do Devyn para quem curte esse estilo mais caótico de enxergar o mundo, com muita zuera.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finalizando...
&lt;/h2&gt;

&lt;p&gt;Decidi fazer esse artigo porque infelizmente sinto que o Brasileiro ainda tem a famosa síndrome do vira-lata em relação a nós mesmos, muitas pessoas preferem um gringo ruim do que um BR bom e nesse artigo eu vim mostrar que existe muita gente foda sim no Brasil, e digo mais, não tem somente eles não, pesquise e você vai descobrir cada vez mais gente absurda fazendo um trabalho maneiro em comunidades e outras redes.&lt;/p&gt;

&lt;p&gt;Se eu falei alguma bobagem sobre os produtores de conteúdos aqui citados gostaria bastante que você mencione aqui nos comentários, meu intuito é apenas espalhar a mensagem da comunidade para mais pessoas.&lt;/p&gt;

&lt;p&gt;Espero que eu tenha te ajudado ao pelo menos encontrar um criador de conteúdo novo por aqui e se você acha que tem outro produtor de conteúdo maneiro que era para está na lista, coloca aqui nos comentários!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
