<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rafael Coelho</title>
    <description>The latest articles on Forem by Rafael Coelho (@racoelho).</description>
    <link>https://forem.com/racoelho</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%2F1217998%2F0970f265-2561-4286-a775-1476bc71af4d.jpeg</url>
      <title>Forem: Rafael Coelho</title>
      <link>https://forem.com/racoelho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/racoelho"/>
    <language>en</language>
    <item>
      <title>RabbitMQ: o que ele faz de verdade (e por que muita gente usa errado)</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Tue, 27 Jan 2026 13:44:53 +0000</pubDate>
      <link>https://forem.com/racoelho/rabbitmq-o-que-ele-faz-de-verdade-e-por-que-muita-gente-usa-errado-265m</link>
      <guid>https://forem.com/racoelho/rabbitmq-o-que-ele-faz-de-verdade-e-por-que-muita-gente-usa-errado-265m</guid>
      <description>&lt;p&gt;RabbitMQ é uma daquelas coisas que &lt;strong&gt;muita gente usa&lt;/strong&gt;, mas pouca gente entende o que tá acontecendo ali no meio.&lt;/p&gt;

&lt;p&gt;A maioria aprende assim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“é só um lugar que você manda uma mensagem&lt;br&gt;
e outro sistema consome depois”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E pronto.&lt;/p&gt;

&lt;p&gt;O problema é que, quando você não entende o &lt;strong&gt;modelo mental do RabbitMQ&lt;/strong&gt; (e o problema que ele resolve), você começa a usar errado.&lt;br&gt;
Ou pior: usa &lt;strong&gt;quando nem precisava&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  O problema real que o RabbitMQ resolve
&lt;/h2&gt;

&lt;p&gt;Imagina uma loja.&lt;/p&gt;

&lt;p&gt;O usuário faz um pedido e o sistema precisa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;registrar o pedido&lt;/li&gt;
&lt;li&gt;processar pagamento (externo)&lt;/li&gt;
&lt;li&gt;emitir nota fiscal (externo)&lt;/li&gt;
&lt;li&gt;atualizar estoque&lt;/li&gt;
&lt;li&gt;enviar e-mail (externo)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se você fizer isso em sequência via HTTP… o usuário fica preso esperando tudo e seu sistema vira um &lt;strong&gt;monólito distribuído&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fluxo típico ruim com HTTP em cadeia
&lt;/h3&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%2Fu3cpu0tgmpnmc5bd6hyd.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%2Fu3cpu0tgmpnmc5bd6hyd.png" alt="Http Flow" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HTTP &lt;strong&gt;acopla tempo&lt;/strong&gt;: um serviço espera o outro.&lt;br&gt;
Se um cair, trava geral. Se um ficar lento, todo mundo sofre.&lt;/p&gt;


&lt;h2&gt;
  
  
  Onde o RabbitMQ entra
&lt;/h2&gt;

&lt;p&gt;Com mensageria, você responde rápido pro usuário e joga o resto pro “tempo do sistema”.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fluxo com RabbitMQ (desacoplado)
&lt;/h3&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%2Fiiod2e8yipyz88m41qrt.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%2Fiiod2e8yipyz88m41qrt.png" alt="RMQ Flow" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RabbitMQ não é “substituto de HTTP”.&lt;br&gt;
Ele existe pra tirar trabalho pesado do caminho do usuário.&lt;/p&gt;


&lt;h2&gt;
  
  
  Modelo mental do RabbitMQ (o principal)
&lt;/h2&gt;

&lt;p&gt;O RabbitMQ segue isso aqui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer → Exchange → Queue → Consumer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E isso é o que quase ninguém guarda:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Producer nunca manda direto pra fila.&lt;/strong&gt;&lt;br&gt;
Ele manda pra uma &lt;strong&gt;Exchange&lt;/strong&gt;, e &lt;strong&gt;a Exchange decide&lt;/strong&gt; pra onde vai.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visão geral do fluxo
&lt;/h3&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%2Fgec32qyqogntdbwcoh9f.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%2Fgec32qyqogntdbwcoh9f.png" alt="General flow" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A fila não pensa.&lt;br&gt;
Quem pensa é a Exchange.&lt;/p&gt;




&lt;h2&gt;
  
  
  Producer, Exchange, Queue, Consumer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Producer&lt;/strong&gt;: quem publica (sua API, um worker, um serviço).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exchange&lt;/strong&gt;: roteia a mensagem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue&lt;/strong&gt;: só armazena (FIFO).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumer&lt;/strong&gt;: processa.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Tipos de Exchange no RabbitMQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Direct Exchange (match exato)
&lt;/h3&gt;

&lt;p&gt;Se a routing key bate, a mensagem vai.&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%2Ffapv9p8w6vjt8owi9kep.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%2Ffapv9p8w6vjt8owi9kep.png" alt="Direct Exchange flow" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  2) Fanout Exchange (broadcast)
&lt;/h3&gt;

&lt;p&gt;Ignora routing key.&lt;br&gt;
Chegou? Espalhou pra todo mundo conectado.&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%2Fcz2p2fc1yfphjdqcfus2.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%2Fcz2p2fc1yfphjdqcfus2.png" alt="Fanout Exchange flow" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3) Topic Exchange (padrões com &lt;code&gt;*&lt;/code&gt; e &lt;code&gt;#&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Aqui você começa a tratar como evento de verdade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;order.created&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order.paid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order.error&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E consumidores podem usar padrões:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;order.*&lt;/code&gt; (uma palavra depois)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;order.#&lt;/code&gt; (zero ou mais palavras depois)&lt;/li&gt;
&lt;/ul&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%2Fo6uuzql6ci494qder1tk.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%2Fo6uuzql6ci494qder1tk.png" alt="Topic Exchange flow" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando você começa a usar Topic bem, seu sistema tende a ficar &lt;strong&gt;mais organizado&lt;/strong&gt; e escalável.&lt;/p&gt;




&lt;h3&gt;
  
  
  4) Headers Exchange (roteamento por cabeçalho)
&lt;/h3&gt;

&lt;p&gt;Em vez de routing key, decide pelo header:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;country=BR&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;locale=pt-BR&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;region=south&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnz6um8j1l5ldogbbvro2.png" alt="Headers Exchange flow" width="800" height="496"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  ACK: por que a mensagem “volta” (e isso é bom)
&lt;/h2&gt;

&lt;p&gt;Aqui separa quem usa RabbitMQ direito de quem perde mensagem em produção.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumiu e deu &lt;strong&gt;ACK&lt;/strong&gt; → remove da fila.&lt;/li&gt;
&lt;li&gt;Consumiu e caiu antes do &lt;strong&gt;ACK&lt;/strong&gt; → volta pra fila.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ACK vs crash
&lt;/h3&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%2Fo7bt17pv0goivct3a07y.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%2Fo7bt17pv0goivct3a07y.png" alt="Ack flow" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Muita gente acha que isso é bug.&lt;br&gt;
Não é. É garantia.&lt;/p&gt;




&lt;h2&gt;
  
  
  RabbitMQ vs Kafka (não confunde)
&lt;/h2&gt;

&lt;p&gt;RabbitMQ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;tarefa&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;garante processamento&lt;/li&gt;
&lt;li&gt;remove mensagem depois do consumo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kafka:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;stream de eventos&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;mantém histórico&lt;/li&gt;
&lt;li&gt;lê quando e quantas vezes quiser&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comparação visual (mental model)
&lt;/h3&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%2Fwj7hfpl4dp9l8gkh3sp4.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%2Fwj7hfpl4dp9l8gkh3sp4.png" alt="Kafka vs RabbitMQ" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RabbitMQ é tarefa.&lt;br&gt;
Kafka é stream.&lt;br&gt;
Usar um no lugar do outro é pedir pra sofrer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quando usar RabbitMQ (e quando não usar)
&lt;/h2&gt;

&lt;p&gt;Use RabbitMQ quando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;precisa desacoplar sistemas&lt;/li&gt;
&lt;li&gt;precisa background / processamento assíncrono&lt;/li&gt;
&lt;li&gt;precisa lidar com falha e retry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Não use quando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;precisa resposta imediata&lt;/li&gt;
&lt;li&gt;o fluxo é simples&lt;/li&gt;
&lt;li&gt;HTTP resolve&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Fechando
&lt;/h2&gt;

&lt;p&gt;RabbitMQ não é complicado.&lt;/p&gt;

&lt;p&gt;O que complica é usar sem entender o modelo.&lt;/p&gt;

&lt;p&gt;Se você entendeu &lt;strong&gt;Producer → Exchange → Queue → Consumer&lt;/strong&gt;,&lt;br&gt;
você já entende RabbitMQ melhor do que muita gente que usa em produção.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://rmq.racoelho.com.br" rel="noopener noreferrer"&gt;Simulador RMQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/tQ2keHRP3vs?si=mwRoPLFdY2y_FiSe" rel="noopener noreferrer"&gt;Veja também o vídeo sobre esse tema&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>O usuário é teu chefe e você precisa deixar ele feliz!</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Thu, 30 Oct 2025 21:54:58 +0000</pubDate>
      <link>https://forem.com/racoelho/o-usuario-e-teu-chefe-e-voce-precisa-deixar-ele-feliz-3k95</link>
      <guid>https://forem.com/racoelho/o-usuario-e-teu-chefe-e-voce-precisa-deixar-ele-feliz-3k95</guid>
      <description>&lt;p&gt;É estranho dizer isso, mas é só você pensar um pouco que você vai entender o que eu quero dizer.&lt;/p&gt;

&lt;p&gt;Quando você baixa um aplicativo ou se cadastra numa plataforma, tudo o que você fizer vai ser pra ver se aquele aplicativo te atende ou simplesmente se você acha a interface bonitinha.&lt;/p&gt;

&lt;p&gt;Aí se a usabilidade for ruim ou não funcionar do jeito que você queria, você vai simplesmente largar e testar outro, não é?&lt;/p&gt;

&lt;p&gt;Agora, vamos pensar que estamos falando do seu sistema:&lt;/p&gt;

&lt;p&gt;se você soubesse que o usuário tá pensando em trocar de app por falta de uma funcionalidade ou por alguma coisa que estava simples demais… o que você faria?&lt;/p&gt;

&lt;p&gt;Se você tiver qualquer tipo de carinho pelo seu app (ou vontade de ganhar dinheiro), você com certeza iria tentar melhorar a experiência dele.&lt;/p&gt;

&lt;p&gt;E pra te ajudar com isso, tem duas coisas que &lt;em&gt;PRECISAM&lt;/em&gt; estar sempre no seu processo de criação:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analisar a experiência do usuário&lt;/strong&gt; e o &lt;strong&gt;“Fator UAU”.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Experiência de Usuário (UX)
&lt;/h2&gt;

&lt;p&gt;Muitas empresas tem uma pessoa responsável por isso, mas não deveria ser só papel dela: é uma coisa que tem que ser pensada desde o começo de qualquer funcionalidade.&lt;/p&gt;

&lt;p&gt;E podem ter muitos UX que vão me xingar por dizer isso, mas pensar em UX não é tão difícil quanto parece (pelo menos do lado dos devs e arquitetos).&lt;/p&gt;

&lt;p&gt;A intenção é fazer a vida do usuário &lt;em&gt;mais fácil&lt;/em&gt; dentro do seu sistema.&lt;/p&gt;

&lt;p&gt;Não tô falando só de como o seu produto vai resolver os problemas dele, mas como vai ser fácil dele entender e conseguir fazer isso.&lt;/p&gt;

&lt;p&gt;E pra atingir uma boa experiência, tem umas perguntas que precisam ser respondidas, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Esse texto explica o que esse botão faz?”&lt;/li&gt;
&lt;li&gt;“Com quantos cliques o usuário consegue fazer isso?”&lt;/li&gt;
&lt;li&gt;“Esse formulário está longo demais?”&lt;/li&gt;
&lt;li&gt;“Dá pra saber bem o que tá acontecendo no sistema o tempo todo?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E são o tipo de pergunta que fazem você pensar como usuário e ver o que parece chato de fazer ou mesmo o que te deixaria confuso.&lt;/p&gt;

&lt;p&gt;Se for difícil pensar assim, aqui vão umas regrinhas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Toda ação precisa de um feedback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O usuário precisa saber que algo aconteceu. &lt;/p&gt;

&lt;p&gt;Se ele clicou num botão e nada mudou, ele vai clicar de novo — e de novo.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Os comportamentos invisíveis precisam ser informados&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se algo está processando, mostre um &lt;em&gt;loading&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Se algo foi salvo, mostre uma confirmação.&lt;/p&gt;

&lt;p&gt;Se os itens da página não carregaram ainda, mostre um Skeleton.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Os erros precisam ser claros e dar um direcionamento&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;“Erro 500” não significa nada pro usuário. &lt;/p&gt;

&lt;p&gt;Diga o que deu errado e o que o usuário pode fazer pra resolver.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Botões precisam dizer o que fazem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Evite ícones aleatórios, labels genéricas (“ver”, “abrir”) ou abreviações internas (“CAD”, “ALT”).&lt;/p&gt;

&lt;p&gt;Use texto direto e que o usuário entenda!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Evite surpresas&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se um botão “Excluir” não pede confirmação, você está pedindo pro usuário cometer erros.&lt;/p&gt;

&lt;p&gt;O usuário precisa saber quando algo é irreversível e precisa ser protegido de cliques em querer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mantenha os assuntos em seus lugares&lt;/p&gt;

&lt;p&gt;Não misture os assuntos pela tela.&lt;/p&gt;

&lt;p&gt;Mantenha todos os botoes e links de pedidos no bloco de pedidos e só!&lt;/p&gt;

&lt;p&gt;Organização visual também é usabilidade.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mantenha consistência entre telas.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se o botão de salvar é verde em uma tela, não o coloque vermelho em outra. &lt;/p&gt;

&lt;p&gt;O cérebro do usuário cria padrões — não bagunce isso!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use padrões conhecidos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Não tente reinventar o botão de fechar ou o ícone de busca. &lt;/p&gt;

&lt;p&gt;UX boa é previsível — e isso é uma virtude.&lt;/p&gt;

&lt;p&gt;E não esqueça: &lt;strong&gt;VERDE é sucesso, AMARELO é alerta e VERMELHO é erro!&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Evite “camadas de cliques”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quanto mais cliques o usuário precisar, maior a chance dele desistir. &lt;/p&gt;

&lt;p&gt;Simplifique o caminho.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Os textos também fazem parte da interface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;“Campo inválido” é diferente de “Ops, o e-mail precisa ter @”. &lt;/p&gt;

&lt;p&gt;UX também é comunicação.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tudo que parece clicável deve ser clicável&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;E o que não for clicável, não deve parecer que é (Essa é clássica, mas muita gente ainda erra).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mostre progresso em ações demoradas&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Upload, importação, geração de relatório… tudo precisa ser mostrado. &lt;/p&gt;

&lt;p&gt;Barra de progresso vai evitar ansiedade.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dê saídas seguras&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sempre deixo o usuário cancelar, voltar, desfazer ou confirmar durante processos irreversíveis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Priorize o que é mais usado&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O botão mais importante não pode estar escondido, tem que ser fácil de ver e de clicar.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Mas ainda podem haver informações que você não vai conseguir só testando ou se perguntando, então você precisa ouvir o que ele tem a dizer.&lt;/p&gt;

&lt;p&gt;E você nem precisa perguntar diretamente pra ter a resposta… você pode monitorar o seu sistema.&lt;/p&gt;

&lt;p&gt;Ver qual dos menus o usuário usa, o fluxo que ele segue sempre que quer criar um novo pedido…&lt;/p&gt;

&lt;p&gt;E ainda pode usar testes A/B: que é quando você coloca 2+ versões da mesma funcionalidade, botão ou texto e observa para descobrir qual converte ou chama mais atenção.&lt;/p&gt;

&lt;p&gt;Assim, você consegue perceber quais são as dores do usuário, quais são os caminhos que ele tá preferindo, qual tá sendo mais difícil de usar e até quais formulários ele tá abandonando no meio do caminho.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fator “UAU”
&lt;/h2&gt;

&lt;p&gt;Depois de garantir que o usuário não vai ter uma experiência ruim, tá na hora de garantir que ele vai ter uma experiência boa usando “O fator UAU”.&lt;/p&gt;

&lt;p&gt;Pensa assim: enquanto pensar na “UX básica” garante que ele não vai largar seu app, o “Fator UAU” vai garantir que ele vai se apaixonar por ele!&lt;/p&gt;

&lt;p&gt;A ideia é simples: você tem que fazer o uso da sua aplicação ser satisfatório.&lt;/p&gt;

&lt;p&gt;Lembra no Super Mario?&lt;/p&gt;

&lt;p&gt;Quando você pega a moedinha, ela não só sumia: ela brilhava e soltava aquele barulhinho — o que deixava pegar moedas uma coisa bem mais satisfatória.&lt;/p&gt;

&lt;p&gt;E você pode fazer a mesma coisa…&lt;/p&gt;

&lt;p&gt;E não tô falando de colocar um efeito sonoro ou efeito especial em tudo.&lt;/p&gt;

&lt;p&gt;E sim em dar “recompensas” para o usuário enquanto ele faz tarefas simples e humanizar um sistema que o usuário precisa pra resolver os problemas dele.&lt;/p&gt;

&lt;p&gt;E isso pode ser feito com coisas simples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Animações que interagem com o usuário&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Como é exemplo da página de login do NPM ou da MetaMask, que o avatar acompanha enquanto você digita, mas tampa os olhos quando você vai digitar a senha.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Textos humanos e “personalizados”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Colocar mensagens que pareçam específicas para aquela pessoa e, quem sabe, levando em consideração coisas como horário, comportamento do usuário, a página de onde ele veio ou até a localização dele.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Micro-animações em botões finais&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pode ser uma animação simples que vai mostrar um ✅, um confete saindo do botão ou um alerta sonoro simples.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Animação de carregamento contextual&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Em vez do spinner genérico, mostrar algo relacionado à ação.&lt;/p&gt;

&lt;p&gt;Ex.: um ícone de avião decolando enquanto o app envia um pedido de viagem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Feedback sonoro ou tátil discreto&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Um toque sutil no celular ao concluir algo com sucesso, ou um som curto quando uma tarefa termina.&lt;/p&gt;

&lt;p&gt;O cérebro entende que deu certo sem nem precisar olhar.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Pode parecer trabalhoso, mas é isso que vai ser a diferença entre um sistema “Ok” e um sistema “UAU”.&lt;/p&gt;

&lt;p&gt;Porque no fim, é isso que faz o usuário perceber que alguém realmente pensou nele.&lt;/p&gt;

&lt;p&gt;É o tipo de detalhe que transforma o uso de um sistema em algo prazeroso — e faz ele querer voltar.&lt;/p&gt;

&lt;p&gt;No fim das contas, é simples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O usuário é teu chefe.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mas se você fizer ele sorrir, &lt;strong&gt;ele vai virar teu fã.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>design</category>
      <category>ui</category>
      <category>ux</category>
    </item>
    <item>
      <title>O que são Observers</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Tue, 05 Nov 2024 20:08:55 +0000</pubDate>
      <link>https://forem.com/racoelho/o-que-sao-observers-4bd5</link>
      <guid>https://forem.com/racoelho/o-que-sao-observers-4bd5</guid>
      <description>&lt;p&gt;O &lt;strong&gt;Observer&lt;/strong&gt; é um Design Pattern de comportamento que te cria um mecanismo de "notificação" para diversos objetos sobre qualquer evento que aconteça no objeto observado.&lt;/p&gt;

&lt;p&gt;Se você já usou Angular ou RxJS, já viu os &lt;code&gt;Observables&lt;/code&gt; da lib do &lt;code&gt;ngrx&lt;/code&gt; que são basicamente uma implementação de um Observer.&lt;/p&gt;

&lt;p&gt;Com o Observer, você cria uma estrutura onde se pode adicionar &lt;strong&gt;observadores&lt;/strong&gt; que vão ser notificados à cada atualização que nem no fluxo abaixo.&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%2F415wg1rtgq6xbw0ynhi1.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%2F415wg1rtgq6xbw0ynhi1.png" alt="Fluxo Observer" width="351" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo prático
&lt;/h3&gt;

&lt;p&gt;Vamos imaginar o seguinte cenário:&lt;/p&gt;

&lt;p&gt;Em um jogo, o jogador pode receber dano, e, ao ocorrer esse evento, diferentes sistemas precisam ser notificados, como a barra de vida, um sistema de áudio para tocar sons de dor, e um sistema de log para registrar o evento.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo de Código
&lt;/h4&gt;

&lt;p&gt;Imagine que estamos desenvolvendo esse sistema em &lt;strong&gt;JavaScript&lt;/strong&gt;, onde o &lt;strong&gt;Jogador&lt;/strong&gt; é o &lt;strong&gt;Observable&lt;/strong&gt; e cada componente que precisa ser notificado (barra de vida, áudio, log de eventos) é um &lt;strong&gt;Observador&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Observable (Jogador)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Jogador&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observadores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// vida inicial do jogador&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Adicionar um observador&lt;/span&gt;
  &lt;span class="nf"&gt;adicionarObservador&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observador&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observadores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observador&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Remover um observador&lt;/span&gt;
  &lt;span class="nf"&gt;removerObservador&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observador&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observadores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observadores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obs&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;obs&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;observador&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Notificar todos os observadores&lt;/span&gt;
  &lt;span class="nf"&gt;notificar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observadores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observador&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;observador&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atualizar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Reduzir a vida e notificar observadores se o jogador sofre dano&lt;/span&gt;
  &lt;span class="nf"&gt;receberDano&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dano&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nx"&gt;dano&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`😨 Jogador recebeu &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dano&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; de dano. Vida atual: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notificar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Observadores&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cada observador representa uma reação específica ao evento de dano e implementa o método &lt;code&gt;atualizar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observador da Barra de Vida:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BarraDeVida&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;atualizar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`📉 Atualizando barra de vida: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; de vida restante.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Observador de Áudio:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SistemaDeAudio&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;atualizar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🔊 Tocando som de dano. Vida atual do jogador: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Observador de Log de Eventos:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogDeEventos&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;atualizar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`📜 Registrando no log: jogador sofreu dano. Vida restante: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;vida&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Uso do Sistema&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agora, vamos criar o &lt;strong&gt;Jogador&lt;/strong&gt; e adicionar observadores para simular as notificações.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instanciar o jogador&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jogador&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Jogador&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Criar observadores&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;barraDeVida&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BarraDeVida&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sistemaDeAudio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SistemaDeAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logDeEventos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LogDeEventos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Adicionar observadores ao jogador&lt;/span&gt;
&lt;span class="nx"&gt;jogador&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adicionarObservador&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;barraDeVida&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;jogador&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adicionarObservador&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sistemaDeAudio&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;jogador&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adicionarObservador&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logDeEventos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Simular o jogador recebendo dano&lt;/span&gt;
&lt;span class="nx"&gt;jogador&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receberDano&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="c1"&gt;// Reduz a vida e notifica observadores&lt;/span&gt;
&lt;span class="nx"&gt;jogador&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receberDano&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="c1"&gt;// Reduz ainda mais e notifica novamente&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A saída será:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;😨 Jogador recebeu 20 de dano. Vida atual: 80
📉 Atualizando barra de vida: 80 de vida restante.
🔊 Tocando som de dano. Vida atual do jogador: 80
📜 Registrando no log: jogador sofreu dano. Vida restante: 80

😨 Jogador recebeu 30 de dano. Vida atual: 50
📉 Atualizando barra de vida: 50 de vida restante.
🔊 Tocando som de dano. Vida atual do jogador: 50
📜 Registrando no log: jogador sofreu dano. Vida restante: 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo, o padrão Observer permite que diferentes partes do sistema de jogo reajam automaticamente ao evento de dano, mantendo o código organizado e facilitando a adição de novos comportamentos.&lt;/p&gt;

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

&lt;p&gt;Para encerrar, o padrão Observer é uma ótima escolha quando você precisa de um sistema que se adapte e responda a eventos em tempo real, permitindo que diferentes componentes reajam a mudanças sem que o código do sujeito principal precise ser alterado.&lt;/p&gt;

&lt;p&gt;Em cenários de jogos, aplicativos de monitoramento e até em redes sociais, o Observer ajuda a criar arquiteturas flexíveis e modulares, facilitando tanto a manutenção quanto a expansão do sistema.&lt;/p&gt;

&lt;p&gt;Esse padrão é amplamente aplicável, seja em interfaces reativas, notificações de eventos ou outros tipos de resposta a mudanças. Ele permite adicionar e remover observadores com facilidade, garantindo que o sistema se mantenha desacoplado e escalável.&lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Como funciona a internet (Parte 2) - O Protocolo HTTP</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Mon, 20 May 2024 15:19:23 +0000</pubDate>
      <link>https://forem.com/racoelho/como-funciona-a-internet-parte-2-o-protocolo-http-3ekp</link>
      <guid>https://forem.com/racoelho/como-funciona-a-internet-parte-2-o-protocolo-http-3ekp</guid>
      <description>&lt;p&gt;Esse post é a continuação da série "Como funciona a internet" onde vamos começar falando do HTTP: A lingagem da WEB&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://racoelho.com.br/posts/como-funciona-a-internet-parte-1"&gt;Parte 1: O Modelo TCP/IP: A Fundação da Internet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Parte 2: O Protocolo HTTP&lt;/li&gt;
&lt;li&gt;Parte 3: Segurança na Internet: Protegendo os Dados (Em breve)&lt;/li&gt;
&lt;li&gt;Parte 4: DNS e Roteamento: Os Nomes da Internet (Em breve)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No &lt;a href="https://racoelho.com.br/posts/como-funciona-a-internet-parte-1"&gt;post anterior&lt;/a&gt;, falamos do TCP como o protocolo mais seguro e confiável para comunicações via sockets de rede.&lt;br&gt;
E nesse post, falaremos do HTTP que é uma implementação do protocolo TCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o protocolo HTTP
&lt;/h2&gt;

&lt;p&gt;O Protocolo &lt;strong&gt;HTTP&lt;/strong&gt; (Hypertext Transfer Protocol) é uma implementação do protocolo TCP para ser usado numa estrutura Server-Client: tendo um servidor que proveria as informações que seriam solicitadas pelo cliente.&lt;/p&gt;

&lt;p&gt;Além das propriedades, ele possui uma estrutura de regras de comunicação para que o servidor e o cliente saibam o que está acontecendo e então poder tomar decisões baseadas nisso.&lt;/p&gt;

&lt;p&gt;Um exemplo clássico disso é o seu navegador agora:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rPIX8o2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-2/http-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rPIX8o2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-2/http-example.png" alt="Exemplo HTTP" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ele enviou uma requisição para o servidor que possui esse site e em seguida recebeu uma resposta que continha o HTML dessa página para então renderizá-la.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Formato HTTP
&lt;/h2&gt;

&lt;p&gt;Para ser mais simples: lembre-se que o HTTP é um &lt;strong&gt;programa&lt;/strong&gt; que é executado para "ouvir" uma porta de rede através do protocolo &lt;strong&gt;TCP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Entendido isso, vamos falar sobre o formato.&lt;/p&gt;

&lt;p&gt;O que o HTTP espera receber é uma sequência de texto que precisa seguir o padrão abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H9gSY30e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-2/http-request-raw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H9gSY30e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-2/http-request-raw.png" alt="Exemplo HTTP" width="766" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Método&lt;/strong&gt;: O método HTTP serve pra explicar o tipo de ação que vai ser feito. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caminho&lt;/strong&gt;: O caminho é a expecificação de qual recurso você está buscando. Por exemplo, em &lt;a href="https://racoelho.com.br/posts"&gt;https://racoelho.com.br/posts&lt;/a&gt;, o caminho é: &lt;code&gt;/posts&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versão HTTP&lt;/strong&gt;: A versão do protocolo HTTP sendo usada para a requisição ou resposta. Hoje em dia, estamos mais familiarizados com o &lt;code&gt;HTTP/2&lt;/code&gt; com o &lt;code&gt;HTTPS&lt;/code&gt;, mas nesse post estaremos usando o &lt;code&gt;HTTP/1.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cabeçalhos&lt;/strong&gt;: Os cabeçalhos passam informações adicionais sobre a requisição ou resposta. Eles seguem o formato "Nome: Valor". Alguns exemplos comuns de cabeçalhos incluem "Host", que especifica o domínio alvo da requisição, e "Content-Type", que especifica o tipo de mídia do corpo da mensagem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E depois da requisição finalizada, o servidor vai reponder no formato abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E499IIM2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-2/http-response-raw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E499IIM2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-2/http-response-raw.png" alt="Exemplo HTTP" width="766" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uma resposta HTTP é composta por três partes principais: a linha de status, os cabeçalhos e o corpo da mensagem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linha de Status&lt;/strong&gt;: Esta é a primeira linha de qualquer resposta HTTP e contém três partes: 

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A versão do protocolo HTTP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Código Status de Resposta:&lt;/strong&gt; É um código que vau de 100 à 599 e serve pra informar o client o resultado da requisição.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mensagem do Status:&lt;/strong&gt; A descrição do Status de Resposta.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cabeçalhos&lt;/strong&gt;: Os cabeçalhos fornecem informações adicionais sobre a resposta. É a mesma ideia da requisição: Eles seguem o formato "Nome: Valor" e cada cabeçalho é separado por uma nova linha. No exemplo, temos os seguintes cabeçalhos:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access-Control-Allow-Origin:&lt;/strong&gt; é um cabeçalho de CORS, ou Cross Origin Resource Sharing, e define quem pode acessar aquele recurso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; indica a data e a hora em que a mensagem foi enviada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection:&lt;/strong&gt; Indica o status da conecção que foi iniciada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content-Type:&lt;/strong&gt; Informa qual é o tipo de conteúdo que será retornado no corpo da resposta.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Corpo da Mensagem&lt;/strong&gt;: Esta é a última parte de uma resposta HTTP e contém os dados reais sendo enviados. No exemplo, o corpo da mensagem é um documento HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Métodos HTTP
&lt;/h2&gt;

&lt;p&gt;HTTP utiliza diferentes métodos de solicitação para especificar a ação desejada. Aqui estão os métodos mais comuns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GET:&lt;/strong&gt; Recupera dados do servidor. Usado para obter páginas web.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;POST:&lt;/strong&gt; Envia dados ao servidor. Comumente usado em formulários.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PUT:&lt;/strong&gt; Atualiza recursos existentes no servidor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DELETE:&lt;/strong&gt; Remove recursos no servidor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Códigos de Status
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Informativas  (100 – 199)&lt;/li&gt;
&lt;li&gt;Sucesso  (200 – 299)&lt;/li&gt;
&lt;li&gt;Redirecionamento (300 – 399)&lt;/li&gt;
&lt;li&gt;Erro de Requisição (400 – 499)&lt;/li&gt;
&lt;li&gt;Erro de Servidor (500 – 599)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para ver uma lista completa, veja esse &lt;a href="https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status"&gt;artigo.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP/2 e HTTP/3
&lt;/h2&gt;

&lt;p&gt;Com o avanço contínuo da web, os protocolos de comunicação também evoluíram para atender às crescentes demandas de desempenho e eficiência. E isso trouxe as melhorias introduzidas pelo HTTP/2 e as inovações do HTTP/3.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/2
&lt;/h3&gt;

&lt;p&gt;HTTP/2, lançado em 2015, foi projetado para melhorar significativamente o desempenho da web em comparação com seu predecessor, HTTP/1.1. Aqui estão algumas das principais melhorias introduzidas pelo HTTP/2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiplexação:&lt;/strong&gt; No HTTP/1.1, cada requisição requer uma nova conexão TCP, o que pode causar lentidão devido à limitação do número de conexões simultâneas. Com HTTP/2, múltiplas requisições podem ser enviadas simultaneamente pela mesma conexão TCP, eliminando o bloqueio de cabeçalho de linha (head-of-line blocking) e melhorando a eficiência.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compressão de Cabeçalhos:&lt;/strong&gt; HTTP/2 utiliza um algoritmo chamado &lt;strong&gt;HPACK&lt;/strong&gt; para comprimir os cabeçalhos das requisições. Como muitos cabeçalhos HTTP se repetem em várias requisições, a compressão reduz significativamente o tamanho dos dados transmitidos, resultando em menor latência e uso de banda.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prioritização de Requisições:&lt;/strong&gt; HTTP/2 permite que os clientes atribuam prioridades às requisições. Isso significa que recursos críticos, como arquivos CSS e JavaScript, podem ser carregados primeiro, melhorando a renderização inicial da página e a experiência do usuário.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Server Push:&lt;/strong&gt; Com o Server Push, um servidor HTTP/2 pode enviar recursos adicionais ao cliente antes mesmo que ele os solicite. Por exemplo, ao solicitar uma página HTML, o servidor pode enviar automaticamente os arquivos CSS e JavaScript necessários, reduzindo o tempo de carregamento da página.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essas melhorias afetam positivamente a performance da web, permitindo tempos de carregamento mais rápidos e uma navegação mais suave para os usuários.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/3
&lt;/h3&gt;

&lt;p&gt;HTTP/3 é a próxima evolução do protocolo HTTP, introduzindo o uso do protocolo &lt;strong&gt;QUIC&lt;/strong&gt; (Quick UDP Internet Connections). &lt;br&gt;
QUIC foi desenvolvido pelo Google e posteriormente adotado pelo &lt;strong&gt;IETF&lt;/strong&gt; (Internet Engineering Task Force) como base para HTTP/3. &lt;br&gt;
Aqui estão algumas das vantagens de HTTP/3 sobre HTTP/2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Baseado em QUIC:&lt;/strong&gt; Diferente de HTTP/2, que utiliza TCP, HTTP/3 é construído sobre o protocolo QUIC, que é baseado em UDP. QUIC foi projetado para fornecer conexões mais rápidas e reduzir a latência, especialmente em redes instáveis ou de alta latência.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redução da Latência de Conexão:&lt;/strong&gt; QUIC elimina o processo de handshake de três vias do TCP e combina a negociação de &lt;strong&gt;TLS&lt;/strong&gt; em uma única etapa, permitindo que as conexões sejam estabelecidas muito mais rapidamente. Isso é particularmente benéfico em dispositivos móveis e redes com altas latências.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiplexação Sem Bloqueio:&lt;/strong&gt; Como HTTP/2, HTTP/3 suporta multiplexação de múltiplas requisições em uma única conexão. No entanto, devido à natureza de UDP, HTTP/3 evita o bloqueio de cabeçalho de linha a nível de transporte, garantindo que a perda de pacotes em uma requisição não afete outras requisições na mesma conexão.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resiliência a Mudanças de Rede:&lt;/strong&gt; QUIC foi projetado para ser resiliente a mudanças de rede, como a transição entre Wi-Fi e redes móveis. Isso é alcançado através da identificação de conexões por IDs de conexão em vez de endereços IP e portas, permitindo que as conexões permaneçam ativas durante a mudança de rede.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  O Uso Atual do HTTP
&lt;/h3&gt;

&lt;p&gt;Hoje em dia, a maioria dos sites utiliza HTTP/2 porque ele traz muitas melhorias em relação ao antigo HTTP/1.1. Essas melhorias, como a capacidade de carregar várias requisições ao mesmo tempo e a compressão de dados, ajudam a tornar os sites mais rápidos. Navegadores e servidores modernos suportam HTTP/2, então muitos desenvolvedores adotaram essa versão sem precisar fazer grandes mudanças no código dos seus sites.&lt;/p&gt;

&lt;p&gt;O HTTP/3 é uma novidade que está ganhando espaço rapidamente. Grandes empresas como Google e Facebook já começaram a usar HTTP/3 para tornar a entrega de conteúdo ainda mais rápida e estável. Com o suporte crescente de navegadores e servidores, é provável que HTTP/3 se torne o padrão nos próximos anos, melhorando a velocidade e a estabilidade da internet, especialmente em redes móveis e conexões mais lentas.&lt;/p&gt;

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

&lt;p&gt;Com a adoção crescente de HTTP/2 e HTTP/3, a internet está se tornando cada vez mais rápida e eficiente, melhorando a experiência dos usuários em todo o mundo. Essas novas versões do protocolo HTTP trazem avanços significativos em termos de performance e estabilidade, especialmente em redes móveis e conexões mais lentas. No entanto, junto com a velocidade e a eficiência, a segurança continua sendo uma preocupação crucial.&lt;/p&gt;

&lt;p&gt;À medida que a internet evolui, garantir a segurança dos dados transmitidos se torna mais importante do que nunca. No próximo post da série "Como funciona a internet", vamos explorar "Segurança na Internet: Protegendo os Dados". Vamos mergulhar nas principais práticas e tecnologias usadas para manter suas informações seguras online, incluindo HTTPS, criptografia, autenticação e as melhores práticas para proteger sua privacidade. Descubra como essas medidas de segurança são implementadas e por que elas são essenciais para uma navegação segura na web. Fique ligado para aprender como proteger seus dados na era digital e garantir que suas interações online sejam sempre seguras e protegidas!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Como funciona a internet (Parte 1): O Modelo TCP/IP: A Fundação da Internet</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Mon, 13 May 2024 15:33:03 +0000</pubDate>
      <link>https://forem.com/racoelho/como-funciona-a-internet-parte-1-o-modelo-tcpip-a-fundacao-da-internet-333f</link>
      <guid>https://forem.com/racoelho/como-funciona-a-internet-parte-1-o-modelo-tcpip-a-fundacao-da-internet-333f</guid>
      <description>&lt;p&gt;Esse será o primeiro post sobre um assunto de extrema importância para todos que querem se aperfeiçoar no desenvolvimento de aplicações para a Web.&lt;br&gt;
Segue a lista das postagens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://racoelho.com.br/posts/como-funciona-a-internet-parte-1"&gt;Parte 1: O Modelo TCP/IP: A Fundação da Internet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://racoelho.com.br/posts/como-funciona-a-internet-parte-2"&gt;Parte 2: HTTP: A Linguagem da WEB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Parte 3: Segurança na Internet: Protegendo os Dados (Em breve)&lt;/li&gt;
&lt;li&gt;Parte 4: DNS e Roteamento: Os Nomes da Internet (Em breve)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para responder a pergunta "Como funciona a internet?", é importante que você saiba o que ela é.&lt;br&gt;
O que chamamos de &lt;em&gt;internet&lt;/em&gt; é uma conexão entre multiplos dispositivos de comunicação, seja por cabo ou não.&lt;/p&gt;

&lt;p&gt;Mas para que eles possam se comunicar, todos precisam "falar a mesma lingua".&lt;br&gt;
Por isso, alguns &lt;strong&gt;protocolos&lt;/strong&gt; de comunicação foram criados como o &lt;strong&gt;UDP&lt;/strong&gt; e o que vamos falar hoje: O Protocolo &lt;strong&gt;TCP&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protocolos e Pacotes
&lt;/h2&gt;

&lt;p&gt;Antes de mergulharmos no TCP, é importante entender o que são protocolos e pacotes, dois conceitos fundamentais na comunicação pela internet.&lt;/p&gt;

&lt;p&gt;Um protocolo é em resumo, um conjunto de regras que vai definir como os dados são transmitidos e recebidos. &lt;br&gt;
É tipo a gramática: ele dita formatos e estruturas de informação para que todos os envolvidos se entendam.&lt;/p&gt;

&lt;p&gt;E quando uma mensagem vai ser enviada de um dispositivo para o outro, ela é dividida em pacotes que serão remontados quando chegarem ao destino.&lt;/p&gt;

&lt;p&gt;Tenha isso em mente para poder entender o próximo tópico.&lt;/p&gt;

&lt;h2&gt;
  
  
  O TCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TCP&lt;/strong&gt;, que significa &lt;strong&gt;Transmission Control Protocol&lt;/strong&gt; (Protocolo de Controle de Transmissão), é um dos principais protocolos de comunicação na Internet por sua segurança de comunicação&lt;br&gt;
E isso é porque ele trabalha com garantias.&lt;/p&gt;

&lt;p&gt;Antes de enviar qualquer informação, ele estabelece a conexão com o destino e aguarda uma resposta.&lt;br&gt;
Esse passo, nós chamamos de "handshake", ou em bom português: "Aperto de mão".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V0jxs_Ie--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-1/tcp-hanshake.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V0jxs_Ie--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-1/tcp-hanshake.png" alt="TCP Hanshake" width="535" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uma vez que a conexão foi garantida, ele começa o envio dos pacotes de maneira ordenada recebendo uma confirmação para cada pacote recebido.&lt;/p&gt;

&lt;p&gt;E o mais importante: caso o dispositivo não receba a confirmação de recebimento, ele vai reenviar aquele mesmo pacote, garantindo que todos os dados cheguem intactos e na ordem correta.&lt;/p&gt;

&lt;h2&gt;
  
  
  O UDP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;UDP&lt;/strong&gt;, que significa &lt;strong&gt;User Datagram Protocol&lt;/strong&gt; (Protocolo de Datagrama do Usuário), é outro protocolo que é conhecido por sua eficiência e velocidade.&lt;/p&gt;

&lt;p&gt;Diferente do TCP, o UDP não estabelece uma conexão antes de enviar informações. &lt;br&gt;
Ele simplesmente envia os pacotes de dados sem sequer saber se vai ser recebido ou não.&lt;br&gt;
Esse processo é conhecido como "fire and forget", ou "dispare e esqueça".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JzwzJBMJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-1/udp-meme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JzwzJBMJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://racoelho.com.br/assets/blog/como-funciona-a-internet-parte-1/udp-meme.png" alt="Meme UDP" width="680" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sem o processo de confirmações, o UDP consegue enviar pacotes de dados muito mais rapido do que o TCP.&lt;/p&gt;

&lt;p&gt;Mas com isso, não existe nenhuma garantia de que todos os pacotes foram recebido ou mesmo que foram ordenados na sequencia correta.&lt;/p&gt;

&lt;p&gt;Apesar disso, o UDP é ideal para situações em que a velocidade é mais importante do que a confiabilidade, como transmissões de vídeo ao vivo ou jogos online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão sobre TCP e a transição para HTTP
&lt;/h2&gt;

&lt;p&gt;Entendendo as funções do TCP e do UDP, fica claro porque o TCP é tão importante para garantir uma comunicação segura e eficiente na internet.&lt;/p&gt;

&lt;p&gt;Através de desse processo burocrático de "handshake" e confirmações, o TCP garante que cada pacote de informação alcance seu destino em perfeita ordem.&lt;/p&gt;

&lt;p&gt;Mas a história não acaba aqui. &lt;/p&gt;

&lt;p&gt;Ainda precisamos falar sobre como esses dados são apresentados e interagem em um ambiente web. &lt;br&gt;
E é aí que o &lt;strong&gt;HTTP&lt;/strong&gt; (Hypertext Transfer Protocol) entra em cena. &lt;/p&gt;

&lt;p&gt;Ele molda a forma como as informações são trocadas e compreendidas entre os navegadores e servidores.&lt;/p&gt;

&lt;p&gt;No próximo post vamos falar sobre ele: &lt;strong&gt;HTTP: A Linguagem da WEB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Vamos explorar como esse protocolo permite que as páginas da web sejam entregues de um servidor para seu navegador, fazendo a internet ser o que ela é hoje.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>development</category>
      <category>internet</category>
    </item>
    <item>
      <title>GitHub Actions e a Magia dos Triggers: Automatizando Tarefas com C#</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Thu, 09 May 2024 00:14:28 +0000</pubDate>
      <link>https://forem.com/racoelho/github-actions-e-a-magia-dos-triggers-automatizando-tarefas-com-c-mle</link>
      <guid>https://forem.com/racoelho/github-actions-e-a-magia-dos-triggers-automatizando-tarefas-com-c-mle</guid>
      <description>&lt;h2&gt;
  
  
  A Ideia
&lt;/h2&gt;

&lt;p&gt;Um dia desses eu estava criando um processo de deploy com &lt;strong&gt;Github Actions&lt;/strong&gt; e me lembrei de um sistema de ITSM que trabalhei que permitia a execução de arquivos de scripts baseado em &lt;strong&gt;triggers&lt;/strong&gt; do sistema.&lt;/p&gt;

&lt;p&gt;E seguindo essa lógica de alteração em sistemas de arquivo que o Github Actions tem, comecei a pensar em algumas possibilidades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatizar backups em horários específicos.&lt;/li&gt;
&lt;li&gt;Realizar upload automáticos de arquivos em determinada pasta&lt;/li&gt;
&lt;li&gt;Limpeza Automática de Disco&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então, abri meu Visual Studio e comecei a criação desse um mini projeto: O &lt;strong&gt;JobExecutor&lt;/strong&gt; &lt;em&gt;(criativo, né?)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A ideia, na verdade é bem simples: teria um arquivo onde nós armazenariamos as triggers ligadas ao script a ser executado.&lt;/p&gt;

&lt;p&gt;Por enquanto, como é apenas uma prova de conceito, decidi usar somente dois tipos de trigger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CronExpression:&lt;/strong&gt; Que é uma forma de você informar periodicidades e é definido por uma string que tem esse formato: &lt;code&gt;* * * * *&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FileWatcher:&lt;/strong&gt; Para que seja executado assim que algum arquivo ou pasta sejam alterados.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para armazenar esses dados, escolhi o JSON e ficou nesse formato aqui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"triggers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FileWatcher"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"scriptFileName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PATH&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;TO&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;FILE.ps1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"watchedPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PATH&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;TO&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;WATCHED&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;FILES"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CronExpression"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"scriptFileName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PATH&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;TO&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;FILE.ps1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"CronExpression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 2 * * *"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Vai&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rodar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;todos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;os&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;às&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;hrs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;da&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;manhã&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você é atento, percebeu que nos dois &lt;code&gt;scriptFileName&lt;/code&gt; eu estou colocando arquivos &lt;code&gt;ps1&lt;/code&gt; que são arquivos de código Poweshell. &lt;br&gt;
Isso é porque pretendo enviar parâmetros para que o usuário possa ter mais detalhes sobre a ação e tomar decisões sobre elas e os scrips de Powershell são completos e simples de se usar.&lt;/p&gt;
&lt;h2&gt;
  
  
  As estruturas de código
&lt;/h2&gt;

&lt;p&gt;Para esse projeto estou usando &lt;strong&gt;C#&lt;/strong&gt;, e como ele é fortemente tipado, encontrar estruturas diferentes dentro do mesmo array seria um problema para ele.&lt;br&gt;
E como não podemos também esperar que o usuário coloque todos os parâmetros que ele não vai precisar, não podemos simplesmente converter de JSON pra objeto diretamente.&lt;/p&gt;

&lt;p&gt;Então, criei quatro classes:&lt;/p&gt;

&lt;p&gt;A primeira tem a inteção de ser a classe "pai", contendo o que todas terão:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Trigger&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ScriptFileName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;CronJobTrigger&lt;/strong&gt; é uma implementação da &lt;strong&gt;Trigger.cs&lt;/strong&gt; e vai adicionar somente o &lt;code&gt;CronExpression&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CronJobTrigger&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Trigger&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CronExpression&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;FileWatcherJobTrigger&lt;/strong&gt; será também uma implementação da &lt;strong&gt;Trigger.cs&lt;/strong&gt;, e vai ter o caminho que vai ser vigiado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileWatcherJobTrigger&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Trigger&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;WatchedPath&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E por fim, a que vai representar o &lt;strong&gt;JSON&lt;/strong&gt; como um todo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TriggerConfig&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Trigger&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;Triggers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Convertendo os diferente tipos de Trigger
&lt;/h2&gt;

&lt;p&gt;Como o FileWatcher e o CronExpression tem parâmetros diferentes, não posso simplemente convertê-los diretamente, já que o conversor vai usar só o tipo &lt;code&gt;Trigger&lt;/code&gt; e ignorar os outros campos.&lt;/p&gt;

&lt;p&gt;Então precisei criar um conversor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Estamos usando o conversor do &lt;a href="https://www.newtonsoft.com/json" rel="noopener noreferrer"&gt;Newtonsoft&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TriggerConverter.cs&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json.Converters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;JobExecutor.Structs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TriggerConverter&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CustomCreationConverter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Trigger&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="nf"&gt;ReadJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JsonReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;objectType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;existingValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jsonObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Trigger&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonObject&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CronExpression"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CronJobTrigger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonObject&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"WatchedPath"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FileWatcherJobTrigger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JsonSerializationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unknown trigger type"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateReader&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui, quando o conversor for passar de item por item ele vai verificar se o campo &lt;code&gt;CronExpression&lt;/code&gt; está preenchido, e caso sim, vai definir o registro como do tipo &lt;code&gt;CronJobTrigger&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O mesmo se aplica para o &lt;code&gt;FileWatcherJobTrigger&lt;/code&gt; e o campo &lt;code&gt;WatchedPath&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Caso nenhum dos dois seja verdade, dispara uma Exception.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Programa
&lt;/h2&gt;

&lt;p&gt;Pra começar, precisamos capturar o arquivo de triggers e ler o conteúdo dele:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Trigger&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;triggers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;configPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"PATH\\TO\\triggers.json"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;LoadTriggers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LoadTriggers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;triggers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ReadTriggerConfig&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Triggers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;TriggerConfig&lt;/span&gt; &lt;span class="nf"&gt;ReadTriggerConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerSettings&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Adicionamos o nosso conversor aqui&lt;/span&gt;
            &lt;span class="n"&gt;Converters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsonConverter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TriggerConverter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;// Aqui, lemos o arquivo com um stream&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StreamReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadToEnd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TriggerConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com as triggers armazenadas na propriedade &lt;code&gt;triggers&lt;/code&gt;, podemos criar o método que vai processar as triggers e executá-las.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;InitializeTriggers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;triggers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"CronExpression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;SetupCronJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;CronJobTrigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"FileWatcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;SetupFileWatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;FileWatcherJobTrigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotImplementedException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Trigger type &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is not implemented."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso, vamos implementar o &lt;code&gt;SetupCronJob&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando o Setup do CronExpression
&lt;/h2&gt;

&lt;p&gt;A expressão Cron é umna string que funciona assim:&lt;/p&gt;

&lt;p&gt;Com 5 caracteres:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* * * * *
- - - - -
| | | | |
| | | | +----- Dia da Semana(0 - 6)
| | | +------- Mês (1 - 12)
| | +--------- Dia do Mês (1 - 31)
| +----------- Hora (0 - 23)
+------------- Minuto (0 - 59)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com 6 Catacteres&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* * * * * *
- - - - - -
| | | | | |
| | | | | +--- Dia da Semana (0 - 6) 
| | | | +----- Mês (1 - 12)
| | | +------- Dia do Mês (1 - 31)
| | +--------- Hora (0 - 23)
| +----------- Minuto (0 - 59)
+------------- Segundo (0 - 59)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com ele você pode dizer "qualquer valor" com um &lt;code&gt;*&lt;/code&gt;, usar uma &lt;code&gt;,&lt;/code&gt; pra definir vários valores ou até um range de valores com um &lt;code&gt;-&lt;/code&gt;.&lt;br&gt;
Exemplos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;12&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; &lt;span class="c1"&gt;# Todos os dias às 12:00&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;8&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; &lt;span class="c1"&gt;# Às 00:05, todos os dias de Agosto&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;15&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;14&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; &lt;span class="c1"&gt;# Todo dia 1º às 14:15&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*/5&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; &lt;span class="c1"&gt;# À cada 5 segundos&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sabendo disso, precisamos converter isso em um agendamento no nosso código.&lt;br&gt;
Pra isso, vamos usar a lib &lt;a href="https://www.nuget.org/packages/ncrontab/" rel="noopener noreferrer"&gt;NCrontab&lt;/a&gt;, &lt;/p&gt;

&lt;p&gt;Vamos usar o método &lt;code&gt;Parse&lt;/code&gt; do &lt;code&gt;CrontabSchedule&lt;/code&gt; e em seguida armazenar a próxima execução.&lt;br&gt;
Vai ficar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CrontabSchedule&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;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CronExpression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CrontabSchedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IncludingSeconds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nextRun&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetNextOccurrence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E depois, vamos criar um &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.threading.timer?view=net-8.0" rel="noopener noreferrer"&gt;&lt;code&gt;System.Threading.Timer&lt;/code&gt; &lt;/a&gt; para agendar a execução do método que irá rodar o script e então reagendar o job novamente.&lt;/p&gt;

&lt;p&gt;O método completo fica assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetupCronJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CronJobTrigger&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CrontabSchedule&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;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CronExpression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CrontabSchedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IncludingSeconds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nextRun&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetNextOccurrence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Executa o arquivo&lt;/span&gt;
            &lt;span class="nf"&gt;ExecuteScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Reagenda o job&lt;/span&gt;
            &lt;span class="nf"&gt;SetupCronJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;nextRun&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;TotalMilliseconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Infinite&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Criando o Setup do FileWatcher
&lt;/h2&gt;

&lt;p&gt;Para verificar as alterações no caminho indicado, nós vamos usar o &lt;a href="https://learn.microsoft.com/pt-br/dotnet/api/system.io.filesystemwatcher?view=net-8.0" rel="noopener noreferrer"&gt;&lt;code&gt;FileSystemWatcher&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;watcher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FileSystemWatcher&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WatchedPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Caminho do arquivo pego na trigger&lt;/span&gt;
    &lt;span class="n"&gt;Filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Monitoraremos todos os arquivos&lt;/span&gt;
    &lt;span class="n"&gt;IncludeSubdirectories&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Incluiremos o monitoramento de subdiretórios&lt;/span&gt;
    &lt;span class="n"&gt;EnableRaisingEvents&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Permitiremos a execução de eventos&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Define os eventos que devem ser notificados&lt;/span&gt;
&lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotifyFilter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastWrite&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileName&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DirectoryName&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Agora, vamos criar o método que vai executar o script e adicioná-lo aos métodos &lt;code&gt;watcher.Changed&lt;/code&gt;, &lt;code&gt;watcher.Created&lt;/code&gt;, &lt;code&gt;watcher.Deleted&lt;/code&gt; e &lt;code&gt;watcher.Renamed&lt;/code&gt; do Watcher.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O Evento de edição pode (e vai) disparar mais de um evento &lt;code&gt;Changed&lt;/code&gt; então, vamos criar um cache para isso.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;scriptExecutionCache&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;


&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetupFileWatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FileWatcherJobTrigger&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;watcher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FileSystemWatcher&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WatchedPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;IncludeSubdirectories&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Incluiremos o monitoramento de subdiretórios&lt;/span&gt;
        &lt;span class="n"&gt;EnableRaisingEvents&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Permitiremos a execução de eventos&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotifyFilter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastWrite&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileName&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DirectoryName&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotifyFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileSystemEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Verifica se pode executar&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ScriptCanBeRunned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Executa o Script&lt;/span&gt;
        &lt;span class="nf"&gt;ExecuteScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Registra a ultima execução&lt;/span&gt;
        &lt;span class="nf"&gt;CacheScriptExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Changed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnChange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Created&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnChange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deleted&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnChange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Renamed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnChange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CacheScriptExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;scriptExecutionCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;ScriptCanBeRunned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;scriptExecutionCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ContainsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;lastExecution&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scriptExecutionCache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Caso tenha executado há mais de 1 segundo, retorna `true`&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lastExecution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O método ExecuteScript
&lt;/h2&gt;

&lt;p&gt;Ele, na verdade, é bem simples.&lt;/p&gt;

&lt;p&gt;Só vai verificar a existência e extensão do arquivo e executálo usando o &lt;a href="https://learn.microsoft.com/pt-br/dotnet/api/system.diagnostics.process?view=net-8.0" rel="noopener noreferrer"&gt;&lt;code&gt;Process&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ExecuteScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Trigger&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"File not found: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".ps1"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotImplementedException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Script type &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is not implemented."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ProcessStartInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FileName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"powershell.exe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"-ExecutionPolicy Bypass -File \"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\""&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso, você só precisará criar o seu script e criar uma trigger para ele.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Caso não saiba fazer scripts com Powershell, leia esse artigo: &lt;a href="https://learn.microsoft.com/pt-br/powershell/module/microsoft.powershell.core/about/about_scripts?view=powershell-7.4#how-to-write-a-script" rel="noopener noreferrer"&gt;about_Scripts&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nesse exemplo, vou criar uma trigger que vai rodar à cada 5 segundos e executar um script que mostra o horário atual.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A trigger&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Triggers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ScriptFileName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PATH&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;TO&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;script.ps1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CronExpression"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"CronExpression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*/5 * * * * *"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;O script:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add-Type -AssemblyName System.Windows.Forms
$now = Get-Date

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resultado:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmagia-dos-triggers-automatizando-tarefas-com-c-sharp%2Fresultado-job-cron-trigger.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmagia-dos-triggers-automatizando-tarefas-com-c-sharp%2Fresultado-job-cron-trigger.png" alt="Resultado Job Cron Trigger"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Melhorias
&lt;/h2&gt;

&lt;p&gt;Uma coisa interessante que pode ser feita é: passar parâmetros para o script.&lt;/p&gt;

&lt;p&gt;Ex: Quando um arquivo for adicionado em uma pasta em específica, enviamos para o script o nome do evento e o nome do arquivo.&lt;/p&gt;
&lt;h3&gt;
  
  
  Passando argumentos
&lt;/h3&gt;

&lt;p&gt;Pra isso, vamos alterar o &lt;code&gt;ExecuteScript&lt;/code&gt; pra receber esses parâmetros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Recebe os parâmetros como uma lista de strings&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ExecuteScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Trigger&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;params&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"File not found: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EndsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".ps1"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotImplementedException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Script type &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is not implemented."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ProcessStartInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FileName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"powershell.exe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Adiciona os parametros no final dos argumentos&lt;/span&gt;
        &lt;span class="n"&gt;Arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"-ExecutionPolicy Bypass -File \"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScriptFileName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\" &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;OnChange:&lt;/strong&gt;&lt;br&gt;
Nele, nós passamos os parâmetros nomeados nesse formado : &lt;code&gt;-{KEY} "{VALUE}"&lt;/code&gt; cmo abaixo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileSystemEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"File &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChangeType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ScriptCanBeRunned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;ExecuteScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="s"&gt;$"-EventType \"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChangeType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="s"&gt;$"-Name \"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="s"&gt;$"-FullPath \"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;CacheScriptExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E no script, nós receberemos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;param (
    [string]$EventType,
    [string]$Name,
    [string]$FullPath
)

Add-Type -AssemblyName System.Windows.Forms

[System.Windows.Forms.MessageBox]::Show("EventType: $EventType`nName: $Name`nFullPath: $FullPath")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmagia-dos-triggers-automatizando-tarefas-com-c-sharp%2Fpassando-parametros-para-o-script.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmagia-dos-triggers-automatizando-tarefas-com-c-sharp%2Fpassando-parametros-para-o-script.png" alt="Passando Parâmetros para o script"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Ainda há muito que pode ser melhorado nesse projeto como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] Criar o arquivo &lt;code&gt;triggers.json&lt;/code&gt; caso ele não exista.&lt;/li&gt;
&lt;li&gt;[x] Adicionar um &lt;code&gt;FileSystemWatcher&lt;/code&gt; no arquivo &lt;code&gt;triggers.json&lt;/code&gt; para atualizar as triggers.&lt;/li&gt;
&lt;li&gt;[ ] Capturar o estado da máquina para poder passar em argumentos para os scripts (Ex: "MemoryUsage" ou "BatteryCharge")&lt;/li&gt;
&lt;li&gt;[ ] Implementar Argumentos para os Jobs de CronExpression&lt;/li&gt;
&lt;li&gt;[ ] Implementar novos tipos de trigger como baseadas em &lt;strong&gt;Eventos do Windows&lt;/strong&gt;, &lt;strong&gt;Emails&lt;/strong&gt; e etc.&lt;/li&gt;
&lt;li&gt;[ ] Transformar em serviço&lt;/li&gt;
&lt;li&gt;[ ] Adicionar sistema de logs&lt;/li&gt;
&lt;li&gt;[ ] Criar interface para adicionar triggers e scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E se você se sentir à vontade, pode me ajudar com a implementação.&lt;br&gt;
Ele já está lá no Github:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rafa-coelho/JobExecutor" rel="noopener noreferrer"&gt;Link do repositório&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>githubactions</category>
      <category>automation</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Introdução ao desenvolvimento Mobile: Guia para Iniciantes</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Sun, 28 Apr 2024 19:31:17 +0000</pubDate>
      <link>https://forem.com/racoelho/introducao-ao-desenvolvimento-mobile-guia-para-iniciantes-178h</link>
      <guid>https://forem.com/racoelho/introducao-ao-desenvolvimento-mobile-guia-para-iniciantes-178h</guid>
      <description>&lt;p&gt;O desenvolvimento mobile é um campo em constante evolução que oferece oportunidades de carreira emocionantes e desafiadoras para desenvolvedores de software. Com o aumento do uso de smartphones e tablets, a demanda por aplicativos móveis está crescendo rapidamente. O desenvolvimento móvel envolve a criação de aplicativos para dispositivos móveis, como smartphones e tablets, usando linguagens de programação específicas para dispositivos móveis.&lt;/p&gt;

&lt;p&gt;Introdução ao Desenvolvimento Mobile é um curso que oferece uma introdução abrangente ao desenvolvimento de aplicativos móveis. O curso aborda os conceitos básicos de desenvolvimento de aplicativos móveis, como plataformas de desenvolvimento, linguagens de programação, arquitetura de aplicativos e design de interface do usuário. Além disso, o curso também abrange tópicos avançados, como desenvolvimento nativo e híbrido, segurança de aplicativos móveis e estratégias de lançamento de aplicativos.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Plataformas de Desenvolvimento Mobile&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;É importante escolher a plataforma de desenvolvimento que melhor atenda às necessidades do projeto. Nesta seção, serão apresentadas as três principais plataformas de desenvolvimento mobile: iOS, Android e Cross-platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;iOS&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O iOS é o sistema operacional móvel da Apple e é utilizado nos dispositivos iPhone e iPad. Para desenvolver aplicativos para iOS, é necessário utilizar a linguagem de programação Swift, que foi desenvolvida pela Apple. Além disso, é possível utilizar o Objective-C, que é uma linguagem mais antiga, mas ainda é suportada pela plataforma.&lt;/p&gt;

&lt;p&gt;Uma das vantagens de desenvolver para iOS é que a plataforma é conhecida por ter usuários mais engajados e dispostos a gastar dinheiro com aplicativos. Além disso, a Apple tem um processo de aprovação rigoroso para os aplicativos que são disponibilizados na App Store, o que garante uma certa qualidade para os usuários.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Android&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O Android é o sistema operacional móvel da Google e é utilizado em uma grande variedade de dispositivos de diferentes fabricantes. Para desenvolver aplicativos para Android, é possível utilizar diversas linguagens de programação, como Java, Kotlin e C++.&lt;/p&gt;

&lt;p&gt;Uma das vantagens de desenvolver para Android é a grande quantidade de dispositivos que utilizam a plataforma. Isso significa que há um grande potencial de alcance para os aplicativos desenvolvidos. Além disso, a Google Play Store é conhecida por ter um processo de aprovação mais simples do que a App Store, o que pode facilitar a disponibilização dos aplicativos.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Cross-platform&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As plataformas de desenvolvimento cross-platform permitem que os desenvolvedores criem aplicativos que possam ser executados em diferentes sistemas operacionais móveis, como iOS e Android. Algumas das principais plataformas de desenvolvimento cross-platform são o Xamarin, o React Native e o Flutter.&lt;/p&gt;

&lt;p&gt;Uma das vantagens de desenvolver para cross-platform é a possibilidade de economizar tempo e recursos, já que é possível desenvolver um único aplicativo que possa ser executado em diferentes plataformas. Além disso, as plataformas de desenvolvimento cross-platform estão em constante evolução e oferecem cada vez mais recursos e funcionalidades para os desenvolvedores.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Linguagens de Programação&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Swift&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Swift é uma linguagem de programação criada pela Apple, lançada em 2014. Ela é utilizada principalmente para desenvolvimento de aplicativos para iOS, macOS, watchOS e tvOS. Swift é uma linguagem de programação moderna, rápida e segura, com uma sintaxe clara e concisa. É uma opção popular para desenvolvedores que desejam criar aplicativos para o ecossistema da Apple.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Kotlin&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Kotlin é uma linguagem de programação criada pela JetBrains, lançada em 2011. Ela é utilizada principalmente para desenvolvimento de aplicativos para Android. Kotlin é uma linguagem moderna, segura e concisa, que se integra perfeitamente com o Java. Ela é uma opção popular para desenvolvedores que desejam criar aplicativos para a plataforma Android.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;JavaScript&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;JavaScript é uma linguagem de programação que é amplamente utilizada em desenvolvimento web e, mais recentemente, em desenvolvimento de aplicativos móveis. Ela é uma linguagem de programação dinâmica, orientada a objetos e baseada em protótipos. JavaScript é uma opção popular para desenvolvedores que desejam criar aplicativos móveis multiplataforma.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Dart&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Dart é uma linguagem de programação criada pela Google, lançada em 2011. Ela é utilizada principalmente para desenvolvimento de aplicativos para o Flutter, um framework de desenvolvimento de aplicativos móveis. Dart é uma linguagem moderna, rápida e segura, com uma sintaxe clara e concisa. Ela é uma opção popular para desenvolvedores que desejam criar aplicativos móveis para iOS e Android com o Flutter.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Ferramentas de Desenvolvimento&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ao desenvolver aplicativos móveis, é essencial ter as ferramentas de desenvolvimento adequadas para garantir um processo suave e eficiente. Nesta seção, serão apresentadas algumas das principais ferramentas de desenvolvimento utilizadas pelos desenvolvedores de aplicativos móveis.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Xcode&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O Xcode é uma ferramenta de desenvolvimento de aplicativos móveis exclusiva para dispositivos iOS e macOS. É um ambiente de desenvolvimento integrado (IDE) que inclui um editor de código, depurador, simulador de dispositivos e outras ferramentas úteis. O Xcode é amplamente utilizado por desenvolvedores de aplicativos iOS devido à sua facilidade de uso e à grande quantidade de recursos disponíveis. Além disso, o Xcode é atualizado regularmente pela Apple para garantir que os desenvolvedores tenham acesso às mais recentes tecnologias e recursos.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Android Studio&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O Android Studio é a principal ferramenta de desenvolvimento de aplicativos móveis para dispositivos Android. É um IDE baseado no IntelliJ IDEA que inclui um editor de código, depurador, emulador de dispositivos e outras ferramentas. O Android Studio é amplamente utilizado por desenvolvedores de aplicativos Android devido à sua facilidade de uso e à grande quantidade de recursos disponíveis. Além disso, o Android Studio é atualizado regularmente pelo Google para garantir que os desenvolvedores tenham acesso às mais recentes tecnologias e recursos.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Visual Studio Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O Visual Studio Code é um editor de código-fonte gratuito e de código aberto desenvolvido pela Microsoft. Embora não seja uma ferramenta de desenvolvimento exclusiva para aplicativos móveis, é amplamente utilizado por desenvolvedores de aplicativos móveis devido à sua velocidade e facilidade de uso. O Visual Studio Code também oferece suporte a uma ampla variedade de extensões e plugins que podem ser usados para melhorar a produtividade do desenvolvedor.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Flutter&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Flutter é um SDK de desenvolvimento de aplicativos móveis de código aberto criado pelo Google. Ele permite que os desenvolvedores criem aplicativos móveis nativos para iOS e Android usando uma única base de código. O Flutter inclui um conjunto completo de widgets personalizados e permite que os desenvolvedores criem interfaces de usuário atraentes e responsivas. Além disso, o Flutter é atualizado regularmente pelo Google para garantir que os desenvolvedores tenham acesso às mais recentes tecnologias e recursos.&lt;/p&gt;

&lt;p&gt;Essas são algumas das principais ferramentas de desenvolvimento de aplicativos móveis utilizadas pelos desenvolvedores. Cada ferramenta tem suas próprias vantagens e desvantagens, e a escolha da ferramenta certa dependerá das necessidades e preferências do desenvolvedor.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Design de Interface&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;O design de interface é uma parte fundamental do desenvolvimento mobile, pois é a primeira impressão que o usuário terá do aplicativo. Uma boa interface deve ser intuitiva, fácil de usar e agradável visualmente.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Material Design&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O Material Design é um conjunto de diretrizes de design criado pela Google. Ele é baseado em um design limpo e moderno, com ênfase em tipografia, cores e imagens. O objetivo é criar uma interface que pareça física, com camadas e sombras. Isso ajuda o usuário a entender a hierarquia das informações na tela.&lt;/p&gt;

&lt;p&gt;Algumas das principais características do Material Design incluem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tipografia clara e legível&lt;/li&gt;
&lt;li&gt;Uso de cores vibrantes e saturadas&lt;/li&gt;
&lt;li&gt;Uso de ícones simples e claros&lt;/li&gt;
&lt;li&gt;Uso de animações sutis para indicar mudanças na interface&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Human Interface Guidelines&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As Human Interface Guidelines (HIG) são um conjunto de diretrizes de design criado pela Apple. Elas são baseadas em um design limpo e minimalista, com ênfase na usabilidade e na consistência. O objetivo é criar uma interface que seja fácil de usar e que pareça familiar para os usuários do iOS.&lt;/p&gt;

&lt;p&gt;Algumas das principais características das HIG incluem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uso de tipografia clara e legível&lt;/li&gt;
&lt;li&gt;Uso de cores suaves e pastéis&lt;/li&gt;
&lt;li&gt;Uso de ícones simples e claros&lt;/li&gt;
&lt;li&gt;Uso de animações sutis para indicar mudanças na interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ao desenvolver um aplicativo, é importante escolher um conjunto de diretrizes de design que se adapte à plataforma escolhida. Isso ajudará a criar uma interface consistente e fácil de usar para os usuários.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Desenvolvimento Front-end&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;O desenvolvimento front-end é uma parte essencial do desenvolvimento mobile. Ele é responsável por criar a interface do usuário, tornando-a agradável e fácil de usar. É através do front-end que o usuário interage com o aplicativo, por isso é importante que ele seja bem projetado e desenvolvido.&lt;/p&gt;

&lt;p&gt;Uma das principais ferramentas usadas no desenvolvimento front-end é o HTML, que é a linguagem usada para criar a estrutura do aplicativo. O CSS é usado para estilizar a interface do usuário, tornando-a visualmente atraente e fácil de usar. O JavaScript é usado para adicionar interatividade à interface do usuário, tornando-a mais dinâmica.&lt;/p&gt;

&lt;p&gt;Além disso, o desenvolvedor front-end deve estar ciente das melhores práticas de design e usabilidade para garantir que o aplicativo seja fácil de usar e agradável aos olhos do usuário. Ele também deve estar ciente das últimas tendências em design de aplicativos móveis para garantir que o aplicativo seja moderno e atualizado.&lt;/p&gt;

&lt;p&gt;Em resumo, o desenvolvimento front-end é uma parte crucial do desenvolvimento mobile. Ele é responsável por criar a interface do usuário, tornando-a agradável e fácil de usar. Para ter sucesso no desenvolvimento front-end, o desenvolvedor deve estar ciente das melhores práticas de design e usabilidade, além de estar atualizado com as últimas tendências em design de aplicativos móveis.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Desenvolvimento Back-end&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;O desenvolvimento back-end é a parte do desenvolvimento mobile responsável pelo gerenciamento de dados e lógica de negócios. É a parte do aplicativo que lida com os servidores, bancos de dados e APIs.&lt;/p&gt;

&lt;p&gt;Para o desenvolvimento back-end, é importante escolher a linguagem de programação adequada. Algumas das linguagens de programação mais populares para o desenvolvimento back-end incluem Java, PHP, Python e Ruby. Cada linguagem tem suas próprias vantagens e desvantagens, por isso é importante escolher a que melhor se adequa às necessidades do projeto.&lt;/p&gt;

&lt;p&gt;Além da escolha da linguagem de programação, também é importante escolher o banco de dados adequado. Alguns dos bancos de dados mais populares para o desenvolvimento back-end incluem MySQL, PostgreSQL e MongoDB. Cada banco de dados tem suas próprias vantagens e desvantagens, e a escolha deve ser feita com base nas necessidades do projeto.&lt;/p&gt;

&lt;p&gt;O desenvolvimento back-end é uma parte crítica do desenvolvimento mobile, pois é responsável pelo gerenciamento de dados e lógica de negócios. Uma boa estratégia de desenvolvimento back-end pode garantir que o aplicativo funcione de forma eficiente e confiável.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Integração com APIs&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A integração com APIs é uma parte crucial do desenvolvimento mobile. APIs, ou Application Programming Interfaces, são conjuntos de rotinas e padrões de programação que permitem que diferentes softwares se comuniquem entre si. No contexto do desenvolvimento mobile, as APIs são usadas para acessar serviços externos, como bancos de dados, sistemas de pagamento e redes sociais.&lt;/p&gt;

&lt;p&gt;Existem várias maneiras de integrar APIs em um aplicativo mobile. Uma das abordagens mais comuns é o uso de bibliotecas de terceiros, que fornecem funcionalidades prontas para uso. As bibliotecas podem ser encontradas em repositórios como o GitHub e o CocoaPods, e geralmente são bem documentadas e testadas.&lt;/p&gt;

&lt;p&gt;Outra opção é criar uma API personalizada para o aplicativo. Isso pode ser feito usando frameworks como o Laravel ou o Express, que permitem criar APIs RESTful de forma fácil e rápida. Uma API personalizada tem a vantagem de ser mais flexível e adaptável às necessidades específicas do aplicativo.&lt;/p&gt;

&lt;p&gt;Independentemente da abordagem escolhida, é importante garantir que a integração com a API seja segura e confiável. Isso pode ser feito usando autenticação e autorização adequadas, validação de entrada de dados e criptografia de dados sensíveis.&lt;/p&gt;

&lt;p&gt;Em resumo, a integração com APIs é uma parte fundamental do desenvolvimento mobile, e existem várias maneiras de implementá-la. Ao escolher uma abordagem, é importante considerar a flexibilidade, a segurança e a confiabilidade da solução.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Testes e Qualidade de Software&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A qualidade do software é essencial para o desenvolvimento mobile. Para garantir que o aplicativo funcione corretamente, é necessário realizar uma série de testes. Os testes são responsáveis por identificar possíveis falhas e garantir que o aplicativo atenda às expectativas do usuário.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Testes Unitários&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Os testes unitários são responsáveis por testar individualmente cada componente do aplicativo. Esse tipo de teste é importante para garantir que o código esteja funcionando corretamente e que não haja erros. Além disso, os testes unitários ajudam a identificar possíveis problemas no código antes mesmo de o aplicativo ser lançado.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Testes de Integração&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Os testes de integração são responsáveis por testar a interação entre os diferentes componentes do aplicativo. Esse tipo de teste é importante para garantir que o aplicativo esteja funcionando corretamente como um todo. Os testes de integração ajudam a identificar possíveis problemas na integração dos diferentes componentes do aplicativo.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Testes de Interface&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Os testes de interface são responsáveis por testar a interface do usuário. Esse tipo de teste é importante para garantir que a interface do usuário esteja funcionando corretamente e que o usuário possa interagir com o aplicativo de forma intuitiva. Os testes de interface ajudam a identificar possíveis problemas na usabilidade do aplicativo.&lt;/p&gt;

&lt;p&gt;Para garantir a qualidade do software, é importante realizar testes em todas as etapas do desenvolvimento. Isso ajuda a identificar possíveis problemas antes mesmo de o aplicativo ser lançado. Além disso, é importante que os testes sejam realizados de forma sistemática e que os resultados sejam documentados para futuras referências.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Publicação e Distribuição&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ao concluir o desenvolvimento de um aplicativo móvel, é hora de publicá-lo e distribuí-lo para que os usuários possam baixá-lo e utilizá-lo. Existem duas principais plataformas de distribuição de aplicativos móveis, a App Store e o Google Play.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;App Store&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A App Store é a loja de aplicativos da Apple, disponível apenas para dispositivos iOS. Para publicar um aplicativo na App Store, é necessário criar uma conta de desenvolvedor da Apple e pagar uma taxa anual. Além disso, o aplicativo deve atender aos padrões de qualidade e segurança da Apple e passar por uma revisão antes de ser aprovado para a publicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Google Play&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O Google Play é a loja de aplicativos do Google, disponível para dispositivos Android. Para publicar um aplicativo na Google Play, é necessário criar uma conta de desenvolvedor do Google e pagar uma taxa única. O aplicativo deve atender às políticas de desenvolvimento do Google e passar por uma revisão antes de ser publicado.&lt;/p&gt;

&lt;p&gt;Ambas as plataformas oferecem ferramentas para gerenciar as atualizações e o desempenho do aplicativo, além de permitir que os desenvolvedores vejam as estatísticas de download e uso. É importante lembrar que a publicação e distribuição de um aplicativo móvel não garante o sucesso, mas é um passo importante para torná-lo disponível para os usuários.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Manutenção e Atualizações&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Manter um aplicativo móvel atualizado é essencial para garantir que ele funcione corretamente e atenda às necessidades dos usuários. A manutenção e atualização do aplicativo podem incluir correção de bugs, melhorias de desempenho e segurança, além de adição de novos recursos.&lt;/p&gt;

&lt;p&gt;Uma das principais razões para manter um aplicativo atualizado é a correção de bugs. Bugs podem causar problemas como falhas no aplicativo, erros de exibição ou problemas de desempenho. Corrigir esses bugs é importante para garantir que o aplicativo funcione corretamente e proporcione uma boa experiência ao usuário.&lt;/p&gt;

&lt;p&gt;Além disso, a manutenção e atualização do aplicativo podem incluir melhorias de desempenho, como otimização de velocidade e redução de consumo de bateria. Isso é importante para garantir que o aplicativo funcione sem problemas em diferentes dispositivos e sistemas operacionais.&lt;/p&gt;

&lt;p&gt;A segurança também é uma consideração importante na manutenção e atualização do aplicativo. As atualizações podem incluir correções de segurança para garantir que o aplicativo esteja protegido contra ameaças externas, como hackers e malware.&lt;/p&gt;

&lt;p&gt;Por fim, a adição de novos recursos é uma maneira de manter o aplicativo relevante e atraente para os usuários. Os novos recursos podem incluir melhorias de usabilidade, novas funcionalidades ou integrações com outras plataformas.&lt;/p&gt;

&lt;p&gt;Em resumo, a manutenção e atualização do aplicativo móvel são essenciais para garantir que ele funcione corretamente, seja seguro e ofereça uma boa experiência ao usuário.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>flutter</category>
      <category>reactnative</category>
      <category>ptbr</category>
    </item>
    <item>
      <title>Sorteio de Amigo Secreto: Sem API, Só Hash</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Thu, 15 Feb 2024 04:03:07 +0000</pubDate>
      <link>https://forem.com/racoelho/sorteio-de-amigo-secreto-sem-api-so-hash-1ccf</link>
      <guid>https://forem.com/racoelho/sorteio-de-amigo-secreto-sem-api-so-hash-1ccf</guid>
      <description>&lt;p&gt;No final do ano de 2023 eu topei participar de um Amigo Secreto da minha familia que, como cada um mora distante do outro, foi sorteado online.&lt;br&gt;
A organizadora nos enviou links onde vimos os nomes de quem tiramos.&lt;/p&gt;

&lt;p&gt;E algo me chamou muita atenção...&lt;/p&gt;

&lt;p&gt;O site pareceu uma aplicação tão simples: Uma plataforma onde você informa uma lista de nomes que terão pares sorteados e links individuais para exibição dos nomes.&lt;/p&gt;

&lt;p&gt;E eis o que me chamou a atenção: &lt;strong&gt;a elegância de uma solução simples.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Então, decidi recriar a mesma aplicação...&lt;/p&gt;
&lt;h2&gt;
  
  
  A ideia
&lt;/h2&gt;

&lt;p&gt;Sempre que penso na construção de uma aplicação, uma das primeiras coisas que penso é: como vou estruturar e armazenar os dados?&lt;/p&gt;

&lt;p&gt;E a resposta para a geração desses links é: não vou!&lt;/p&gt;

&lt;p&gt;O sorteado não precisa de muito mais do que o nome da pessoa que ele sorteou, certo? Então, é só o que vamos mandar para ele!&lt;/p&gt;

&lt;p&gt;E quanto ao dono do sorteio?&lt;/p&gt;

&lt;p&gt;Bem... ele talvez precise ver novamente alguma informação daquele Amigo Secreto. Então, podemos persistir de uma forma que só ele veja, assim, não precisando de nenhuma centralização de dados.&lt;/p&gt;
&lt;h2&gt;
  
  
  O projeto
&lt;/h2&gt;

&lt;p&gt;A aplicação teria 4 telas&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inicial: onde o usuário veria a lista de seus sorteios já criados.&lt;/li&gt;
&lt;li&gt;Formulário de Criação do Amigo Secreto.&lt;/li&gt;
&lt;li&gt;Tela de visualização: Onde o usuário veria cada nome atrelado a um botão de "Enviar Link".&lt;/li&gt;
&lt;li&gt;Tela de revelação: onde o sorteado veria o nome da pessoa que sorteou.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Escolhi usar &lt;strong&gt;NextJS&lt;/strong&gt; e usar o &lt;strong&gt;IndexedDB&lt;/strong&gt; para persistência local.&lt;/p&gt;
&lt;h3&gt;
  
  
  1 - Formulário de Criação
&lt;/h3&gt;

&lt;p&gt;Sim, vamos começar com ele.&lt;/p&gt;

&lt;p&gt;Pensei um pouco sobre como seria para adicionar multiplos nomes e fiquei dividido entre um input baseado em &lt;em&gt;Tags&lt;/em&gt; usando algum separador:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Finput-em-tags.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Finput-em-tags.png" alt="Input Em Tags"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E entre multiplos inputs seguidos por um botão de "adicionar outro" como abaixo:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Fmultiplos-inputs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Fmultiplos-inputs.png" alt="Multiplos Inputs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E no fim acabei optando pela segunda opção.&lt;/p&gt;

&lt;p&gt;E agora, após o usuário apertar para enviar, a aplicação precisa gerar o sorteio e gerar os hashs para o link.&lt;/p&gt;

&lt;p&gt;Então, precisamos de um método que que sorteie e outro que gere os hashs.&lt;br&gt;
Esse foi o resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Pair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Método chamado no onSubmit&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortPairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;Pair&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;_pairs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pair&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Reordena aleatoriamente&lt;/span&gt;
  &lt;span class="nx"&gt;_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_names&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Monta o par com a próxima index&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nx"&gt;_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_names&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Chama o método de encriptação&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encryptNamePair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;_pairs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;hash&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_pairs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o &lt;code&gt;encryptNamePair&lt;/code&gt;, que recebe dois nomes, só precisa concatená-los e converter e &lt;strong&gt;base64&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O formato antes da conversão ficaria mais ou menos assim: "Nome1-Nome2", para que a gente saiba a quem pertence o link.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptNamePair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;namesJoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;n1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/ /g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;n2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/ /g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;unescape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;namesJoint&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E quanto a persistência local, decidi usar o &lt;strong&gt;IndexedDB&lt;/strong&gt; do próprio navegador.&lt;/p&gt;

&lt;p&gt;Pra isso, criei uma classe &lt;code&gt;IndexedDBManager&lt;/code&gt; para gerenciar as chamadas.&lt;br&gt;
Não vou perder muito tempo explicando, porque é tudo muito padrão aqui.&lt;br&gt;
Mas o código ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// IndexedDBManager.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IndexedDBManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Informações do banco local&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RcSecretSantaDB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;dbVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IDBDatabase&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secretSantas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Método de conexão&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;connect &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;indexedDB&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbVersion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Erro ao abrir o banco de dados.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;IDBOpenDBRequest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onupgradeneeded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;IDBOpenDBRequest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objectStoreNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;keyPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Método de inserção&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;addEditItem &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Banco de dados não conectado.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;readwrite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Erro ao adicionar/editar item no banco de dados.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então, no método &lt;code&gt;onSumbit&lt;/code&gt; do formulário eu só preciso chamar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IndexedDBManager&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dbManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEditItem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pairs&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E pronto. Nossos Amigos Secretos já podem ser salvos!&lt;/p&gt;

&lt;h3&gt;
  
  
  2 - Home - Listagem de Amigos Secretos
&lt;/h3&gt;

&lt;p&gt;Ela só precisa de três coisas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uma lista dos Amigos Secretos &lt;/li&gt;
&lt;li&gt;Um botão para excluir um item&lt;/li&gt;
&lt;li&gt;Um link para visualizar um item em específico&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para buscar os dados do &lt;strong&gt;IndexedDB&lt;/strong&gt; só é necessário o método abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// IndexedDBManager.ts&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getItems &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Banco de dados não conectado.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;readonly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;IDBRequest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Erro ao obter itens do banco de dados.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E para o caso de o usuário querer excluir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// IndexedDBManager.ts&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;deleteItem &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Banco de dados não conectado.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readwrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Erro ao excluir item do banco de dados.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3 - Visualização de Amigo Secreto
&lt;/h3&gt;

&lt;p&gt;Essa é a minha favorita.&lt;/p&gt;

&lt;p&gt;Ela precisa capturar o dado do &lt;code&gt;IndexedDB&lt;/code&gt; e apresentar os nomes dos participantes atrelados à um link.&lt;/p&gt;

&lt;p&gt;A minha ideia foi criar um botão de compartilhamento onde haveria uma mensagem explicando basicamente o contexto da mensagem e fornecendo o link.&lt;/p&gt;

&lt;p&gt;Vamos lá... Primeiramente, precisamos recuperar o item.&lt;br&gt;
A tela recebe a ID gerada pela tela de criação e envia para o método &lt;code&gt;getItemById&lt;/code&gt; que vai retornar o Objeto de &lt;code&gt;SecretSanta&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// IndexedDBManager.ts&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;getItemById&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Banco de dados não conectado.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readonly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onsuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;IDBRequest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Erro ao obter item do banco de dados.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso, adicionei a listagem dos nomes e criei um componente &lt;code&gt;SharedButton&lt;/code&gt; que é bem simples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ShareButton.tsx&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IShareButtonProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;className&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ShareButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;IShareButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleShare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;share&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;text&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Web Share API não é suportada neste navegador.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleShare&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o adicionei no &lt;code&gt;[id].tsx&lt;/code&gt; assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SecretSanta&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hostLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pairs&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="nx"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="c1"&gt;// ....&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ShareButton&lt;/span&gt;
              &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enviar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;`Você foi adicionado ao Amigo Secreto: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"!\nE aqui está o seu link:\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hostLink&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;}/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que fica mais ou menos assim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Fmessage-whatsapp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Fmessage-whatsapp.png" alt="Mensagem Whatsapp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4 - A tela de revelação
&lt;/h3&gt;

&lt;p&gt;Ela é a mais simples de todas.&lt;br&gt;
Como o link contem o hash, só precisamos recuperá-lo, desencriptar e então separar os nomes.&lt;/p&gt;

&lt;p&gt;E fazemos isso com o método abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decryptNamePair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encodedStr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decodedString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encodedStr&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decodedString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;decodedString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\+&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// [hash].tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decryptNamePair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após receber os nomes, tudo o que precisamos é exibi-los na tela de uma forma amigável.&lt;br&gt;
E eu escolhi fazer assim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Fresultado.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fsorteio-de-amigo-secreto%2Fresultado.png" alt="Resultado Amigo Secreto"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Esse foi um projeto rápido que me deixou bem satisfeito por tamanha simplicidade.&lt;br&gt;
Projetos assim, me provam que nem tudo precisa ser complexo ou mega elaborado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O melhor sistema é o que funciona! Não se esqueça disso!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depois de completo, eu ainda gastei um tempinho refinando e adicionando tradução, mas acho que não tem muito mais o que mexer nele.&lt;/p&gt;

&lt;p&gt;Fique à vontade para olhar usar ou ver o código fonte:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://secret-santa.racoelho.com.br" rel="noopener noreferrer"&gt;Acesse - Amigo Secreto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rafa-coelho/amigo-secreto" rel="noopener noreferrer"&gt;Código Fonte&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Jabá:
&lt;/h3&gt;

&lt;p&gt;Veja esse e outros posts no meu blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://racoelho.com.br" rel="noopener noreferrer"&gt;Blog Racoelho&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>node</category>
      <category>typescript</category>
    </item>
    <item>
      <title>De 35 à 3 segundos: Melhorando a Performance de um Relatório</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Wed, 14 Feb 2024 15:17:58 +0000</pubDate>
      <link>https://forem.com/racoelho/de-35-a-3-segundos-melhorando-a-performance-de-um-relatorio-14l9</link>
      <guid>https://forem.com/racoelho/de-35-a-3-segundos-melhorando-a-performance-de-um-relatorio-14l9</guid>
      <description>&lt;p&gt;Um belo dia, recebo um ticket que reclamava de algo:&lt;br&gt;
&lt;strong&gt;Relatório está demorando demais&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Contexto
&lt;/h2&gt;

&lt;p&gt;Estou em um projeto de um SaaS onde se coleta centenas de sinais por minuto para serem inseridos no database do &lt;strong&gt;BigQuery&lt;/strong&gt; e que, eventualmente, são processados para geração de relatórios.&lt;/p&gt;

&lt;p&gt;No caso desse post, os relatório em questão busca os dados das viagens geradas por um motorista em um determinado intervalo de tempo e compara seu desempenho com o restante da frota.&lt;/p&gt;
&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Este sistema ainda está em desenvolvimento e homologação, então, muitas decisões foram tomadas sem o mesmo volume de dados ou criados às pressas para melhorias futuras.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  O Problema
&lt;/h2&gt;

&lt;p&gt;Com o aumento do uso, o volume de dados aumentou e eventualmente algumas lentidões foram notadas:&lt;br&gt;
O relatório, quando buscado num intervalo de 7 dias, tomava cerca de &lt;strong&gt;30 segundos&lt;/strong&gt; para devolver a resposta.&lt;/p&gt;

&lt;p&gt;E com este ticket foi traçada uma meta: resposta em 3 segundos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solucionando
&lt;/h2&gt;

&lt;p&gt;Com isso dito, comecei a analisar o código para procurar os pontos mais lentos.&lt;br&gt;
Usando um &lt;code&gt;Stopwatch&lt;/code&gt;, metrifiquei cada etapa do relatório para descobrir que dos 35 segundos da minha request, &lt;em&gt;metade&lt;/em&gt; ocorria em 2 buscas ao banco que aconteciam no inicio do processo da Service.&lt;/p&gt;

&lt;p&gt;Em resumo, a função recebia um StartDateTime e um EndDateTime e um identificador do veículo e realizava uma lógica parecida com a abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
&lt;span class="c1"&gt;// Busca todas as viagens da frota&lt;/span&gt;
&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VehicleTrip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fleetTrips&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTripsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Filtra as viagens daquele veículo em específico&lt;/span&gt;
&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VehicleTrip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fleetTrips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VehicleId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;vehicleId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Busca uma lista de eventos para ocorridos na viagem&lt;/span&gt;
  &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEventsAsync&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Instancia o objeto de retorno onde é processada a média dos dados&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reportResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ReportExample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vehicleTrips&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fleetTrips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Realizava a comparação de desempenho individual com o da frota inteira&lt;/span&gt;
  &lt;span class="n"&gt;reportResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CalculatePercentageDifferenceToTheFleet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fleetTrips&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reportResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você deu uma boa olhada, já deve ter conseguido encontrar onde estão pelo menos dois dos gaps.&lt;/p&gt;

&lt;p&gt;Então, vamos para o primeiro:&lt;/p&gt;

&lt;h3&gt;
  
  
  Alterando o facade.GetTripsAsync()
&lt;/h3&gt;

&lt;p&gt;Como pode perceber, esse método captura todos os dados de todos os veículos da frota e só os usaria no final do processo, o que me pareceu um esforço desnecessário.&lt;/p&gt;

&lt;p&gt;Claro, até havia caching. Assim, nos momentos em que era necessário buscar a quantidade de eventos críticos ou mesmo realizar alguma filtragem, os dados já estavam lá.&lt;/p&gt;

&lt;p&gt;Mas mesmo assim, as informações que não seriam exclusivamente do veículo não pareciam ser necessárias em outro momento além daquele método &lt;code&gt;CalculatePercentageDifferenceToTheFleet&lt;/code&gt; onde seriam comparadas as médias de desempenho entre o Veículo e a Frota para informações como: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"O veículo está consumindo, em média, &lt;em&gt;X&lt;/em&gt;% a mais do que a frota"&lt;/li&gt;
&lt;li&gt;"O veículo está andando, em média, &lt;em&gt;X&lt;/em&gt;% a mais rápido do que a frota"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E não há necessidade de calcular a média da frota no código, uma vez que podemos buscá-la diretamente no banco.&lt;/p&gt;

&lt;p&gt;Então essas foram as primeiras alterações: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O método foi atualizado para buscar unicamente os dados do veículo ;&lt;/li&gt;
&lt;li&gt;Criação do método &lt;code&gt;facade.GetFleetStats()&lt;/code&gt; para retornar as médias de toda a frota sem a necessidade de listar os dados;&lt;/li&gt;
&lt;li&gt;Adaptação do método &lt;code&gt;CalculatePercentageDifferenceToTheFleet&lt;/code&gt; para receber o objeto retornado do &lt;code&gt;facade.GetFleetStats&lt;/code&gt; ao invés da listagem de trips;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
&lt;span class="c1"&gt;// Busca todas as viagens do veículo&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetVehicleTripsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vehicleId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Busca uma lista de eventos para ocorridos na viagem&lt;/span&gt;
  &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEventsAsync&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Executa o calculo das médias de sinais da Frota&lt;/span&gt;
&lt;span class="n"&gt;FleetStats&lt;/span&gt; &lt;span class="n"&gt;fleetStats&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFleetStatsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Instancia o objeto de retorno onde é processada a média dos dados&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reportResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ReportExample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vehicleTrips&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fleetStats&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Método alterado para receber FleetStats ao invés de IEnumerable&amp;lt;VehicleTrip&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;reportResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CalculatePercentageDifferenceToTheFleet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fleetStats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reportResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o resultado foi: resposta média da API em 18 segundos.&lt;br&gt;
Bom? Eu não achei.&lt;/p&gt;

&lt;p&gt;O que me levou para a segunda alteração.&lt;/p&gt;
&lt;h3&gt;
  
  
  Removendo multiplas chamadas ao facade.GetEventsAsync()
&lt;/h3&gt;

&lt;p&gt;Para cada uma das viagens, a aplicação precisa buscar os eventos gerados dentro do intervalo dela.&lt;br&gt;
E como já deve ter pensado por conta própria, realizar uma chamada assíncrona para cada uma das trips não era a melhor solução... então a alteração foi bem intuitiva e rápida:&lt;/p&gt;

&lt;p&gt;Este código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetVehicleTripsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vehicleId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEventsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VehicleId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Foi substituido por este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEventsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetVehicleTripsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vehicleId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTimeUTC&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartDateTime&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
                    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTimeUTC&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndDateTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o resultado?&lt;br&gt;
Resposta media de: 14 segundos.&lt;br&gt;
Ainda não chegamos na meta, mas estávamos à caminho.&lt;/p&gt;
&lt;h3&gt;
  
  
  Ajustando a busca no banco
&lt;/h3&gt;

&lt;p&gt;Neste momento, eu fiz dezenas de alterações em queries tentando diminuir os dados processados e conversões.&lt;br&gt;
O que só deve ter reduzido uma média de 2 segundos.&lt;/p&gt;

&lt;p&gt;E onde estavam os gaps????? Nos MESMOS lugares: nas comunicações com o BigQuery.&lt;br&gt;
Seria isso um problema de performance do mecanismo?&lt;/p&gt;

&lt;p&gt;Eu tinha certeza que não, mas o Stopwatch me dizia claramente: nenhuma outra operação leva sequer &lt;strong&gt;1s&lt;/strong&gt;  enquanto as comunicações com o BigQuery levam em média &lt;strong&gt;6s&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Então, fui olhar a implementação da classe de conexão.&lt;/p&gt;

&lt;p&gt;Aqui vai uma pequena explicação:&lt;/p&gt;

&lt;p&gt;A classe &lt;code&gt;BigQuery.cs&lt;/code&gt; que vou mostrar faz parte dos building blocks da aplicação e precisa ser genérico ao ponto de converter os dados nos formatos corretos das propriedades.&lt;/p&gt;

&lt;p&gt;O código que encontrei foi parecido com esse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;BigQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetQueryResultsAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bigQueryClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bqClientFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;bigQueryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateQueryJobAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Lista de retorno&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bigQueryRows&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;bigQueryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetQueryResultsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reference&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;bigQueryRows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SafeTotalRows&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Para cada linha retornada do banco...&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BigQueryRow&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bigQueryRows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// Converte a linha para o objeto T chamando o método de ParseRow.&lt;/span&gt;
      &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParseRow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Adiciona na lista que será retornada&lt;/span&gt;
      &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O primeiro problema a ser explorado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O uso do &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se você não sabe como o List funciona, aqui vai uma breve explicação...&lt;/p&gt;

&lt;p&gt;Para a criação de um array você precisa fornecer o tamanho dele, ou seja, quantos itens ele poderá guardar e este tamanho será imutável!&lt;/p&gt;

&lt;p&gt;Ex.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tamanho do arr: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Tamanho do arr: 8&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arr2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tamanho do arr2: {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Tamanho do arr2: 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas porque não precisamos informar um tamanho para o List?&lt;br&gt;
Quando você gera um List, ele cria um array de tamanho &lt;strong&gt;0&lt;/strong&gt; e quando você adiciona itens dentro dele com o &lt;code&gt;.Add()&lt;/code&gt; ele gera um &lt;strong&gt;NOVO&lt;/strong&gt; array com tamanho &lt;strong&gt;4&lt;/strong&gt;, vai atribuir o valor do array anterior ao novo e descartar o velho.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"E se eu rodar o &lt;code&gt;.Add()&lt;/code&gt; 5 vezes?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ele criará um novo array de tamanho &lt;strong&gt;8&lt;/strong&gt; e assim seguirá: todas as vezes que exceder o tamanho, um novo array será criado com o DOBRO do tamanho que vai receber o valor do antigo que será descartado.&lt;/p&gt;

&lt;p&gt;Ex.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Itens: {0}, Capacidade: {1}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Capacity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Itens: 0, Capacidade: 0&lt;/span&gt;

&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Itens: {0}, Capacidade: {1}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Capacity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Itens: 1, Capacidade: 4&lt;/span&gt;

&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Itens: {0}, Capacidade: {1}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Capacity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Itens: 5, Capacidade: 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já entendeu o problema?&lt;br&gt;
Então, haverão vários cenários em que teremos dados duplicados em dois arrays diferentes.&lt;br&gt;
E quanto maior a lista tratada, maior o tempo de processamento e a memória alocada.&lt;/p&gt;

&lt;p&gt;Então, a alteração foi a seguinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A remoção do &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A substituição do foreach por um &lt;code&gt;.Select()&lt;/code&gt; com conversão direta&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O que deixou o metódo mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;BigQuery&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetQueryResultsAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bigQueryClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bqClientFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;bigQueryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateQueryJobAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bigQueryRows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SafeTotalRows&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;bigQueryRows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParseRow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E qual foi o resultado disso?????????&lt;br&gt;
Uma resposta média de &lt;strong&gt;6 segundos!!!!!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nesse momento eu olhei pra trás, e vendo que a versão anterior ainda conseguia levar até 40 segundos, eu quase me senti satisfeito com o resultado....&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Quase.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Isso porque o ticket dizia "3 segundos".&lt;br&gt;
O que me levou a analizar o método &lt;strong&gt;ParseRow&lt;/strong&gt; que é chamado pelo método que acabamos de alterar.&lt;/p&gt;
&lt;h3&gt;
  
  
  Analisando o ParseRow
&lt;/h3&gt;

&lt;p&gt;Ele tem uma função bem simples: &lt;br&gt;
Ao receber a linha, ele deve instanciar o genério &lt;strong&gt;T&lt;/strong&gt; e iterar sobre cada uma das colunas da &lt;strong&gt;row&lt;/strong&gt; e buscá-la nas propriedades de &lt;strong&gt;T&lt;/strong&gt;.&lt;br&gt;
Veja:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;BigQuery&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;ParseRow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;BigQueryRow&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Criação de instância do genérico&lt;/span&gt;
  &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateInstance&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Armazena todas as propriedades do objeto&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;typeProperties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Loop para iterar cada coluna...&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Armazena nome e valor do campo&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RawRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Confere se a coluna atual existe no objeto&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;matchingProperty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;typeProperties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// Caso não encontre ou não tenha valor... skip.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matchingProperty&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Converte e atribui dados conforme o tipo da propriedade &lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E a pergunta principal foi "O que dá pra melhorar?" e a resposta estava na variável &lt;code&gt;typeProperties&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ela armazena cada uma das propriedades do objeto &lt;strong&gt;T&lt;/strong&gt;, mas isso acontece para cada uma das linhas retornadas do banco... o que quer dizer que se houver um resultado de 1800 linhas para um objeto de 12 propriedades.... bem, você entendeu.&lt;/p&gt;

&lt;p&gt;Então, a melhor solução é fazer a aplicação buscar uma única vez e reutilizar a informação coletada.&lt;/p&gt;

&lt;p&gt;E como o método &lt;code&gt;GetQueryResultsAsync&lt;/code&gt; é chamado algumas vezes durante o processo e durante todo o ciclo de vida da aplicação, melhor do que armazenar numa unica variável seria criar uma tabela como caching.&lt;/p&gt;

&lt;p&gt;O que deixou o código mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;BigQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ConcurrentDictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PropertyInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_typePropertiesCache&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ConcurrentDictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PropertyInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;ParseRow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;BigQueryRow&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateInstance&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;typeProperties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;typeProperties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_typePropertiesCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetOrAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="cm"&gt;/*
      [...]
  */&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, a aplicação armazenaria uma única vez as informações de um objeto e nunca mais o consultaria, poupando armazenamento e tempo de processamento.&lt;/p&gt;

&lt;p&gt;E agora, meus amigos...&lt;br&gt;
Com isso, chegamos a marca média dos........................................&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.2 segundos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNGI1bGRncWFtZTlmd2x1OGN6Y25uemI1c3I5ajVkOXo0NnMzcno5cCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/t3sZxY5zS5B0z5zMIz/giphy-downsized-large.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNGI1bGRncWFtZTlmd2x1OGN6Y25uemI1c3I5ajVkOXo0NnMzcno5cCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/t3sZxY5zS5B0z5zMIz/giphy-downsized-large.gif" alt="UHUL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas ainda faltava algo...&lt;a href=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Threading
&lt;/h3&gt;

&lt;p&gt;Depois de tudo isso, ainda havia uma coisa que poderia ser alterada lá na Service.&lt;/p&gt;

&lt;p&gt;Das 3 chamadas ao facade, somente uma delas precisava da resposta de outra.&lt;/p&gt;

&lt;p&gt;Então, não havia a necessidade de esperar chamada por chamada para montar o resultado desde que eu garanta que todas foram executadas.&lt;/p&gt;

&lt;p&gt;E com isso em mente, nosso código da service foi atualizado para algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
&lt;span class="c1"&gt;// Declaração das chamadas&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;eventsTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEventsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vehicleTripsTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetVehicleTripsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vehicleId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;fleetStatsTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;facade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFleetStatsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Aguardando a execução de todas simultâneamente&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventsTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vehicleTripsTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fleetStatsTask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Aplicando o "await" da task que já está completa&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;eventsTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Aplicando o "await" da task que já está completa&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vehicleTrips&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;vehicleTripsTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTimeUTC&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartDateTime&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
                    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTimeUTC&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndDateTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Aplicando o "await" da task que já está completa&lt;/span&gt;
&lt;span class="n"&gt;FleetStats&lt;/span&gt; &lt;span class="n"&gt;fleetStats&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;fleetStatsTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reportResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ReportExample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vehicleTrips&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fleetStats&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;reportResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CalculatePercentageDifferenceToTheFleet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fleetStats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reportResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Com isso, eu decidi rodar mais uma vez a versão existente e compará-la com a minha.&lt;/p&gt;

&lt;p&gt;E esses foram os resultados:&lt;/p&gt;

&lt;p&gt;A versão antes da mudança:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmelhorando-a-performance-de-um-relatorio%2Fstaging.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmelhorando-a-performance-de-um-relatorio%2Fstaging.jpg" alt="Staging"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A versão atualizada:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmelhorando-a-performance-de-um-relatorio%2Fdev.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fracoelho.com.br%2Fassets%2Fblog%2Fmelhorando-a-performance-de-um-relatorio%2Fdev.jpg" alt="Dev"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExeTI5eTBmcHBjcWlkZnF0OGJjYm95aTlxd2xxaGk5bHZoeDNuZng5NiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/YprQElVsTlnbztuWv4/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExeTI5eTBmcHBjcWlkZnF0OGJjYm95aTlxd2xxaGk5bHZoeDNuZng5NiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/YprQElVsTlnbztuWv4/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Jabá
&lt;/h3&gt;

&lt;p&gt;Veja esse e outros posts no meu blog pessoal: &lt;br&gt;
&lt;a href="//racoelho.com.br/blog"&gt;racoelho.com.br/blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>braziliandevs</category>
      <category>performance</category>
    </item>
    <item>
      <title>Construí um jogo de Jokenpô com WebSockets</title>
      <dc:creator>Rafael Coelho</dc:creator>
      <pubDate>Sun, 03 Dec 2023 20:52:05 +0000</pubDate>
      <link>https://forem.com/racoelho/construi-um-jogo-de-jokenpo-com-websockets-2fml</link>
      <guid>https://forem.com/racoelho/construi-um-jogo-de-jokenpo-com-websockets-2fml</guid>
      <description>&lt;p&gt;Esses dias, postei naquela rede que as pessoas inventam cargos e termos um teste que eu fiz com WebSockets: Um jogo de Jokenpô.&lt;/p&gt;

&lt;p&gt;Projeto bobo? Sim, mas se é de pequenas doses de dopamina que os viciados em Tiktok se movem, eu também posso.&lt;/p&gt;

&lt;p&gt;A ideia era só brincar com WS mesmo, mas eu cheguei a me empolgar tanto que quando percebi, estava fazendo protótipos para um app mobile que eu tenho CERTEZA que eu nunca iria fazer.&lt;/p&gt;

&lt;p&gt;Então, decidi largar de mão e só fiz uma UI simples com html que só tem 3 botões e um quadro para ver o placar e a opção selecionada pelo oponente.&lt;/p&gt;

&lt;p&gt;A parte que mais gostei de fazer nele foi o Criador de Partidas:&lt;br&gt;
Quando você se conecta, ele te coloca numa fila aguardando outro jogador para poder montar uma "sala" onde vai começar uma partida de Melhor de Três.&lt;/p&gt;

&lt;p&gt;Queria dar uma evoluída nele eventualmente, mas tô sentindo que não vou 😅 (pelo menos, não tão cedo).&lt;/p&gt;

&lt;p&gt;Bem, sintam-se livres a dar uma olhada e contribuir, se quiserem:&lt;br&gt;
&lt;a href="https://github.com/rafa-coelho/jokenpo"&gt;https://github.com/rafa-coelho/jokenpo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eu hospedei ele no render também (pode demorar pra startar o pod deles):&lt;br&gt;
&lt;a href="https://jokenpo.racoelho.com.br/"&gt;https://jokenpo.racoelho.com.br/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Segue uns prints dele:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BBRmO1qb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6xfi0v6nbgmrayzjgk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BBRmO1qb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6xfi0v6nbgmrayzjgk1.png" alt="Searching Room" width="683" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kc8_q39e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zs16qgcghozkxhrkhq2j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kc8_q39e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zs16qgcghozkxhrkhq2j.png" alt="Playing" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RoSsKQ_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gw9ok0r3u6xmr02hgcnl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RoSsKQ_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gw9ok0r3u6xmr02hgcnl.png" alt="Match Result" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
