<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jean Cabral</title>
    <description>The latest articles on DEV Community by Jean Cabral (@jeancabral).</description>
    <link>https://dev.to/jeancabral</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%2F190308%2F4e3568f7-f24e-4505-9205-e6afa55e2b8f.jpg</url>
      <title>DEV Community: Jean Cabral</title>
      <link>https://dev.to/jeancabral</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeancabral"/>
    <language>en</language>
    <item>
      <title>Inteligência emocional</title>
      <dc:creator>Jean Cabral</dc:creator>
      <pubDate>Thu, 02 Apr 2026 13:21:20 +0000</pubDate>
      <link>https://dev.to/jeancabral/inteligencia-emocional-218o</link>
      <guid>https://dev.to/jeancabral/inteligencia-emocional-218o</guid>
      <description>&lt;p&gt;Inteligência emocional não diz respeito a “não ficar estressado”, “não errar” ou “estar sempre tranquilo".&lt;/p&gt;

&lt;p&gt;Trata-se de perceber as situações antes de ultrapassar limites e ter a maturidade para mudar de direção.&lt;/p&gt;

&lt;p&gt;Nos ambientes profissionais, o desafio é o tempo todo fazer entregas, cumprir prazos, gerar qualidade técnica e ser útil do ponto de vista produtivo.&lt;/p&gt;

&lt;p&gt;Entretanto, existe uma característica que baseia todas essas coisas e que não costuma ser falada, que é a capacidade de lidar com relacionamentos, frustrações, pressão e consigo mesmo.&lt;/p&gt;

&lt;p&gt;Em minha trajetória, algumas aprendizagens ficaram claras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Nem toda resposta precisa ser dada na hora.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Saber a hora certa para falar é tão importante quanto ter coragem para fazer conversas difíceis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Estar certo e estabelecer boas relações nem sempre andam juntas. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pedir desculpas é sinal de maturidade e não de fraqueza.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pessoas boas vão ter crescimento. Pessoas boas e emocionalmente equilibradas irão liderar.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No fundo, a carreira não é uma corrida de 100 metros. Ela é uma maratona.&lt;/p&gt;

&lt;p&gt;E quem não aprende a lidar com suas emoções não terá condições de dar conta do crescimento a longo prazo.&lt;/p&gt;

&lt;p&gt;Inteligência emocional não é soft skills.&lt;/p&gt;

&lt;p&gt;É career skill.&lt;/p&gt;

</description>
      <category>inteligenciaemocional</category>
      <category>careerdevelopment</category>
      <category>management</category>
    </item>
    <item>
      <title>Baixar a branch do PR: quando vale a pena testar localmente?</title>
      <dc:creator>Jean Cabral</dc:creator>
      <pubDate>Sun, 06 Jul 2025 23:57:00 +0000</pubDate>
      <link>https://dev.to/jeancabral/baixar-a-branch-do-pr-quando-vale-a-pena-testar-localmente-1f2m</link>
      <guid>https://dev.to/jeancabral/baixar-a-branch-do-pr-quando-vale-a-pena-testar-localmente-1f2m</guid>
      <description>&lt;p&gt;&lt;strong&gt;“Você costuma baixar a branch do PR para testar localmente?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Essa pergunta parece simples, mas pode render boas discussões sobre qualidade de código, eficiência nas revisões e confiança no processo de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Nem todo pull request precisa ser executado localmente e quando isso se torna uma prática comum para todo PR, talvez o problema esteja em outro lugar.&lt;/p&gt;

&lt;p&gt;Neste artigo, trago algumas reflexões sobre &lt;strong&gt;quando faz sentido testar um PR localmente&lt;/strong&gt; e como isso se encaixa com a &lt;strong&gt;&lt;a href="https://www.morling.dev/blog/the-code-review-pyramid" rel="noopener noreferrer"&gt;Pirâmide do Code Review&lt;/a&gt;&lt;/strong&gt; uma abordagem (fantástica) que propõe uma hierarquia de prioridades ao revisar pull requests, inspirada na lógica da Pirâmide de Maslow.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 A Pirâmide do Code Review
&lt;/h2&gt;

&lt;p&gt;Antes de falar de testar localmente, vale conhecer essa estrutura simples que define &lt;strong&gt;níveis de prioridade em uma revisão de código&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Base da pirâmide (Functionality &amp;amp; Implementation)&lt;/strong&gt; – O código faz o que deveria fazer?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segunda camada (Testability &amp;amp; Coverage Tests)&lt;/strong&gt; – O código está bem testado? É fácil de testar?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terceira camada (Readability e Maintainability)&lt;/strong&gt; – Dá para entender e manter esse código?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topo da pirâmide (Code Style)&lt;/strong&gt; – O código segue o padrão do time?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Essa pirâmide nos ajuda a revisar com foco no que realmente importa, e só subir a escada se os degraus abaixo estiverem ok.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Quando vale a pena testar localmente?
&lt;/h2&gt;

&lt;p&gt;Baixar a branch e rodar localmente &lt;strong&gt;faz sentido quando você está na base ou na segunda camada da pirâmide&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Implementação
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;O PR mexe em regras críticas (ex: valores financeiros, autenticação)?&lt;/li&gt;
&lt;li&gt;Há dúvidas se o código faz realmente o que deveria?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Testabilidade
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Os testes cobrem bem os casos de uso?&lt;/li&gt;
&lt;li&gt;Existem fluxos manuais ou side effects que não estão claros no PR?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Outros motivos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;É um PR que muda o comportamento da UI ou da API e você quer ver na prática.&lt;/li&gt;
&lt;li&gt;O CI está instável e você quer validar o funcionamento local.&lt;/li&gt;
&lt;li&gt;A descrição do PR está vaga, e rodar ajuda a entender o contexto.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ❌ Quando isso pode virar um problema?
&lt;/h2&gt;

&lt;p&gt;Se você &lt;strong&gt;sente necessidade de testar todo PR localmente&lt;/strong&gt;, pode haver sinais de alerta:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Os testes automatizados não cobrem bem o código.&lt;/li&gt;
&lt;li&gt;Os PRs não explicam claramente o que foi feito.&lt;/li&gt;
&lt;li&gt;O CI não é confiável ou não tem validação de comportamento.&lt;/li&gt;
&lt;li&gt;O código não é previsível: pequenas mudanças geram efeitos inesperados.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se testar localmente se torna regra, é sinal de alerta: talvez o problema não esteja no código, mas na confiança no processo (e isso custa tempo).&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ Prós e contras de testar localmente
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Pontos positivos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Dá mais confiança para aprovar.&lt;/li&gt;
&lt;li&gt;Ajuda a pegar side effects.&lt;/li&gt;
&lt;li&gt;Facilita entender contextos complexos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ❌ Pontos negativos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Torna a revisão mais lenta e pesada.&lt;/li&gt;
&lt;li&gt;Cria dependência de ambiente local e setups manuais.&lt;/li&gt;
&lt;li&gt;Pode mascarar problemas na qualidade do código ou na cobertura de testes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔁 E se o tempo for curto?
&lt;/h2&gt;

&lt;p&gt;Use o bom senso. Nem todo PR precisa de execução local. Se for pequeno, direto e bem testado, &lt;strong&gt;a leitura de código pode ser suficiente&lt;/strong&gt;. Confie na pirâmide: valide se a implementação corrige/cobre o problema de negócio, avalie os testes e só depois pense em rodar algo manualmente.&lt;/p&gt;




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

&lt;p&gt;Testar a branch do PR localmente é uma prática útil (mas não obrigatória). Ela deve ser usada com critério, como uma ferramenta de apoio para validar o que a leitura de código ou os testes automatizados não respondem sozinhos.&lt;/p&gt;

&lt;p&gt;A pergunta que fica é:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Você testa localmente por necessidade, ou por desconfiança do processo?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se for a segunda opção, talvez seja hora de investir em testes melhores, pipelines mais confiáveis e PRs mais bem descritos.&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%2F4m45iy8xzumcg8zer7pq.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%2F4m45iy8xzumcg8zer7pq.png" alt="Imagem da Pirâmide do Code Review" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>cleancode</category>
      <category>produtividade</category>
      <category>boaspráticas</category>
    </item>
    <item>
      <title>Retornando ao C# e explorando as inovações com C# in Depth</title>
      <dc:creator>Jean Cabral</dc:creator>
      <pubDate>Fri, 27 Sep 2024 13:29:02 +0000</pubDate>
      <link>https://dev.to/jeancabral/retornando-ao-c-e-explorando-as-inovacoes-do-c-9-com-c-in-depth-k2d</link>
      <guid>https://dev.to/jeancabral/retornando-ao-c-e-explorando-as-inovacoes-do-c-9-com-c-in-depth-k2d</guid>
      <description>&lt;p&gt;Após um período distante da programação e atuando em uma posição de gestão, decidi retomar os estudos de C#. No meu último contato com a linguagem, ela estava na versão 5, em 2014. Desde então, muita coisa mudou no ecossistema .NET, e senti a necessidade de me atualizar, especialmente em um cenário de carreira em Y, onde equilibrar habilidades técnicas e de liderança é essencial.&lt;/p&gt;

&lt;p&gt;Neste post, trago um resumo do capítulo 15 do livro &lt;a href="https://csharpindepth.com/" rel="noopener noreferrer"&gt;C# in Depth&lt;/a&gt; de Jon Skeet, um dos grandes nomes da comunidade .NET. Este capítulo aborda as principais inovações do C# 9, lançado em 2020. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Embora a quarta edição do livro cubra até o C# 8 (publicada em 2019), os conceitos apresentados são uma base sólida para entender a evolução da linguagem até versões mais recentes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Por que voltar ao C#?
&lt;/h2&gt;

&lt;p&gt;Depois de um período na cadeira de gerente, senti uma desconexão com algumas práticas e tecnologias atuais. O avanço rápido da tecnologia exige que, mesmo em posições de liderança, continuemos nos atualizando tecnicamente. Assim, retomar o C# foi uma forma de recuperar a confiança nas ferramentas modernas que estão sendo usadas no mercado e fortalecer minhas habilidades na linguagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principais Funcionalidades do C# 9
&lt;/h2&gt;

&lt;p&gt;O capítulo 15 de C# in Depth foca nas inovações do C# 9 que aprimoram o design de objetos imutáveis e introduzem novos paradigmas, como a programação funcional. Aqui estão as funcionalidades mais relevantes discutidas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Records:&lt;/strong&gt; Um novo tipo de referência que facilita a criação de objetos imutáveis, oferecendo igualdade baseada em valor e suporte a "with-expressions". Records são uma ótima escolha quando precisamos de classes que representem dados, com menos verbosidade.&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;pessoa1&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;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cabral"&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;pessoa2&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;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cabral"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Comparação baseada em valor&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="n"&gt;pessoa1&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pessoa2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// True&lt;/span&gt;

&lt;span class="c1"&gt;// Uso de with-expressions para copiar com modificações&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pessoa3&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pessoa1&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Gama"&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="n"&gt;pessoa3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Output: Person { FirstName = Jean, LastName = Gama }&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;Person&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;FirstName&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;LastName&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;Propriedades init-only:&lt;/strong&gt; Propriedades que só podem ser configuradas durante a inicialização de um objeto. Isso permite um design mais seguro e imutável, reforçando a ideia de que, após criado, o estado do objeto não deve mudar.&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;Product&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;Name&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;init&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;decimal&lt;/span&gt; &lt;span class="n"&gt;Price&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;init&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product&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;Product&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;"MacBook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;9200.00M&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// O código abaixo gera erro de compilação, pois a propriedade `init` não pode ser alterada após a inicialização&lt;/span&gt;
&lt;span class="c1"&gt;// product.Name = "ThinkPad";&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Padrões aprimorados:&lt;/strong&gt; O C# 9 introduziu novas possibilidades para correspondência de padrões, incluindo padrões lógicos e correspondência em tuplas. Esses recursos melhoram a legibilidade e expressividade do 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="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetGroupSizeMessage&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;peopleCount&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;peopleCount&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Poucas pessoas."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Pequeno grupo de pessoas."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Médio grupo de pessoas."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Grande grupo de pessoas."&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Padrões lógicos em tuplas&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ClassifyPerson&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;name&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;age&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Menor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Adulto"&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="nf"&gt;GetGroupSizeMessage&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="c1"&gt;// Output: Pequeno grupo de pessoas.&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="nf"&gt;ClassifyPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// Output: Adulto&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="nf"&gt;ClassifyPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// Output: Menor&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essas inovações refletem o quanto o C# evoluiu para oferecer mais segurança, concisão e expressividade, alinhando-se às demandas modernas de programação.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Nunca é tarde para aprender algo novo e recomeçar, seja para aprimorar nossas habilidades ou redescobrir a paixão pelo código.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Até breve.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>development</category>
      <category>learning</category>
      <category>csharpindepth</category>
    </item>
    <item>
      <title>Primeiros passos com o Apache Airflow</title>
      <dc:creator>Jean Cabral</dc:creator>
      <pubDate>Tue, 04 May 2021 12:17:40 +0000</pubDate>
      <link>https://dev.to/jeancabral/primeiros-passos-com-o-apache-airflow-53oj</link>
      <guid>https://dev.to/jeancabral/primeiros-passos-com-o-apache-airflow-53oj</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Olar pessoal! Tive a oportunidade de conhecer o Apache Airflow e como achei muito bacana resolvi aprofundar um pouco nos conceitos dessa ferramenta. Este artigo vai ser algo bem introdutório, vou expor aqui alguns conceitos básicos sobre seu funcionamento, instalação e a criação de um fluxo de trabalho.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/apache/airflow" rel="noopener noreferrer"&gt;Airflow&lt;/a&gt; é uma plataforma criada pelo Airbnb, escrita em Python, que se tornou open-source em 2015 e logo depois cedida para o Apache Foundation. &lt;/p&gt;

&lt;p&gt;O Airflow é um orquestrador de fluxos de tabalho. Com ele podemos programar, agendar e monitorar consultas de diversas fontes de dados, fazer tratamentos de forma simples. Veja alguns exemplos de casos de uso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criar um schedule, de forma periódica ou não, de migração de dados de uma tabela para outra;&lt;/li&gt;
&lt;li&gt;Importar dados a partir de várias fontes e unificar em uma base centralizada.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Instalando
&lt;/h2&gt;

&lt;p&gt;Primeiramente você deve ter um ambiente funcional com Python 3 antes de prosseguir ou se preferir rodar através do &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/start/docker.html" rel="noopener noreferrer"&gt;docker compose&lt;/a&gt; disponivel no site do Apache Airflow. &lt;/p&gt;

&lt;p&gt;Optei pela instalação local para ficar mais didático. Iremos fazer a instalação do Airflow em  sua versão estável (v2.0.2).  Conforme sugerida em sua documentação oficial devemos fazer sua instalação usando o comando &lt;code&gt;pip&lt;/code&gt;, ou seja,  &lt;code&gt;poetry&lt;/code&gt; e &lt;code&gt;pip-tools&lt;/code&gt; não são recomendados.&lt;/p&gt;

&lt;p&gt;Crie um diretório, onde ficará o projeto.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;apache-airflow
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;apache-airflow
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate


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

&lt;/div&gt;

&lt;p&gt;Agora vamos instalar o airflow, execute o comando abaixo:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;apache-airflow


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

&lt;/div&gt;

&lt;p&gt;Após a instalação, iremos definir uma variável de ambiente que indica onde o airflow está instalado.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AIRFLOW_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Agora vamos inicializar o ambiente.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;airflow db init


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

&lt;/div&gt;

&lt;p&gt;Após executar esse passo, notamos que ele cria o arquivo de configuração, um banco de dados sqlite onde será armazenados os metadados dos workflows, o arquivo de configuração do Airflow webserver e a um diretório de logs.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AIRFLOW_HOME

├── airflow.cfg

├── airflow.db

├── logs

└── webserver_config.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Antes de subir o servidor do airflow, primeiramente vamos criar um usuário via cli do airflow, conforme o exemplo abaixo e definir sua senha.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;airflow &lt;span class="nb"&gt;users &lt;/span&gt;create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--username&lt;/span&gt; admin &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--firstname&lt;/span&gt; Jean &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--lastname&lt;/span&gt; Cabral &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--role&lt;/span&gt; Admin &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--email&lt;/span&gt; seumelhor@email.com


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

&lt;/div&gt;

&lt;p&gt;Definindo o acesso, vamos agora subir o nosso servidor e acessar o Dashboard, executando o  comando abaixo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;airflow webserver &lt;span class="nt"&gt;-p&lt;/span&gt; 8084


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

&lt;/div&gt;

&lt;p&gt;No comando acima estou executando o servidor na porta 8084, caso o parametro port nao seja passado ele será executado na porta padrão 8080. Para ver mais parametros execute &lt;code&gt;airflow webserver --help&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Depois de efetuar o login, podemos ver a lista todos os workflows que vem por 'default' na instalação da ferramenta como exemplos, que servem de base para construirmos nossas pipelines. É possível ocultar esses exemplos alterando a propriedade &lt;code&gt;load_examples&lt;/code&gt; no arquivo &lt;code&gt;airflow.cfg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O Dashboard do Airflow é bem intuitivo, através dele podemos ter controle das execuções e o histórico de cada um deles, log de execução, gráficos e etc.&lt;/p&gt;

&lt;p&gt;Antes de criarmos o nosso primeiro Workflow, vamos ver uns conceitos importantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ETL&lt;/strong&gt;: (Extract, Transform, Load): Procedimento geral para copiar de uma ou mais fontes de dados para um determinado destino;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DAG&lt;/strong&gt;: (Directed Acyclic Graph): Coleção de todas as tarefas a serem executadas, organizadas de forma que reflete a relação e dependências entre elas. Em termos simples, a DAG é uma coleção de todas as pequenas tarefas que se unem para realizar uma grande tarefa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Operator&lt;/strong&gt;: Enquanto a DAG define como o fluxo vai ser executado, o Operator define o que será feito;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BashOperator&lt;/strong&gt;: Executa comandos no bash&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PythonOperator&lt;/strong&gt;: Usado para chamar python function na DAG&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EmailOperator&lt;/strong&gt;: Envio de email&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SimpleHttpOperator&lt;/strong&gt;: Fazer requisições HTTP&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Task&lt;/strong&gt;: Instância de um Operator em execução;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Worker&lt;/strong&gt;: Unidade de Trabalho (processo, container ou serviço) que realiza o processamento de uma tarefa de cada vez;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scheduler&lt;/strong&gt;: Unidade de agendamento requerido para orquestrar a execução de trabalhos agendados;&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Criando nosso workflow
&lt;/h2&gt;

&lt;p&gt;O fluxo de trabalho pode ser um cálculo simples, uma consulta no banco de dados, comando bash, script python, consultas Postgres, consultas BigQuery, etc. O fluxo de trabalho é dividido em uma ou mais tarefas que se relacionam entre si e formam um DAG.&lt;/p&gt;

&lt;p&gt;Vamos criar um diretório chamado &lt;code&gt;dags&lt;/code&gt; e dentro dele iremos criar um script python chamado &lt;code&gt;print_date_file.py&lt;/code&gt;, que fará o seguinte: criar um arquivo texto num dado diretório e escrever a data atual.&lt;/p&gt;

&lt;p&gt;Vamos ao código&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;airflow&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;airflow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DAG&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;airflow.operators.bash_operator&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BashOperator&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Essas são as libs que iremos utilizar em nossa DAG. Como iremos usar o BashOperator precisamos importar ela da biblioteca do airflow.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="n"&gt;default_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;owner&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;airflow&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start_date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;airflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days_ago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Em &lt;code&gt;default_args&lt;/code&gt; podemos definir um dicionário de parametros padrão que serão passados para o construtor de cada tarefa.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="n"&gt;dag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DAG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;dag_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;save_date_in_file_txt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;default_args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;default_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;schedule_interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&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="n"&gt;dagrun_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;print_date_file&lt;/span&gt;&lt;span class="sh"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# Imprime a data na saída padrão.
&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BashOperator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;print_date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bash_command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dag&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Cria a pasta tmp caso ela não exista.
&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BashOperator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;make_directory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bash_command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mkdir -p /home/jean/Code/PlayGround/apache-airflow/tmp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dag&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Faz uma sleep de 5 segundos.
&lt;/span&gt;&lt;span class="n"&gt;t3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BashOperator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sleep&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bash_command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sleep 5&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dag&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Salve a data em um arquivo texto.
&lt;/span&gt;&lt;span class="n"&gt;t4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BashOperator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;save_date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bash_command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date &amp;gt; /home/jean/Code/PlayGround/apache-airflow/tmp/date_output.txt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dag&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Veja que nas tasks (t1, t2, t3 e t4) são valores que estão chamando a classe &lt;code&gt;BashOperator&lt;/code&gt; e recebe os argumentos necessários para execução.&lt;/p&gt;

&lt;p&gt;Cada tarefa tem seu &lt;code&gt;task_id&lt;/code&gt; que define de forma única uma tarefa e argumentos necessários com base no operador que estamos utilizando.&lt;/p&gt;

&lt;p&gt;Em nosso DAG, estamos executando quatro tasks diferentes, a primeira está imprime a data na stdout, a segunda cria o diretório tmp; a t3 faz uma pausa de 5 segundos e a última cria um arquivo texto, escreve a data, e é armazenado no diretório que criamos na t2.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t4&lt;/span&gt; &lt;span class="c1"&gt;#Fluxo de execução das tasks
&lt;/span&gt;

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

&lt;/div&gt;

&lt;p&gt;Portanto, seu t1 óbvio deve ser executado antes de t2, portanto, definimos um fluxo de execução das tarefas.&lt;/p&gt;

&lt;p&gt;Por fim, precisamos colocar nosso arquivo print_date_file.py na pasta DAG e, em seguida, ele será carregado no servidor automaticamente.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkni43gkw1afgjrnd5cut.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkni43gkw1afgjrnd5cut.png" alt="DAG print_date_file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Em Graph View podemos ver a visualização do gráfico de tarefas:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm49539qplo92nctvarzz.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm49539qplo92nctvarzz.png" alt="Graph View"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Veja que a 'seta' indica a relação de dependência. Na task  &lt;code&gt;make_directory&lt;/code&gt; depende de &lt;code&gt;print_date&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Bem, este foi um exemplo muito simples de como criamos tarefas e executamos o fluxo de trabalho. O intuíto foi trazer uma visão geral do Airflow, e o potencial que ele tem para auxiliar a criação de fluxos de trabalho em geral.&lt;/p&gt;

&lt;p&gt;Até mais!&lt;/p&gt;

</description>
      <category>airflow</category>
      <category>etl</category>
      <category>workflow</category>
      <category>python</category>
    </item>
    <item>
      <title>GatsbyJS: Configurando Eslint e Prettier no Visual Studio Code</title>
      <dc:creator>Jean Cabral</dc:creator>
      <pubDate>Fri, 14 Feb 2020 18:18:07 +0000</pubDate>
      <link>https://dev.to/jeancabral/gatsbyjs-configurando-eslint-e-prettier-no-visual-studio-code-5ab8</link>
      <guid>https://dev.to/jeancabral/gatsbyjs-configurando-eslint-e-prettier-no-visual-studio-code-5ab8</guid>
      <description>&lt;p&gt;Olá Pessoal! Neste artigo vamos configurar nosso editor para padronizar e formatar nosso código de forma automática, deixando-nos livres para pensar sobre a funcionalidade do nosso app.&lt;/p&gt;

&lt;p&gt;Para isso, usaremos duas ferramentas. O &lt;strong&gt;ESLint&lt;/strong&gt; que é um plugin utilizado para padronizar nosso código, como por exemplo a utilização de ponto e vírgula, tamanho máximo de caracteres em linhas dentre outros; e o Prettier que é utilizado para formatação do código deixando ele pretty, ou seja, 'bonito' 😀💅&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙ Setup
&lt;/h2&gt;

&lt;p&gt;Suponho que você já tenha o &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt; instalado e as extensões habilitadas &lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint"&gt;ESLint&lt;/a&gt; e &lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode"&gt;Prettier&lt;/a&gt; e um projeto &lt;a href="https://www.gatsbyjs.org/"&gt;GatsbyJS&lt;/a&gt; inicializado.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Instalando o ESLint como dependência do projeto
&lt;/h3&gt;

&lt;p&gt;Execute comando abaixo para instalar osso package principal de linting o  &lt;strong&gt;ESLint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;$ yarn add eslint -D&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Não precisaremos instalar o &lt;strong&gt;Prettier&lt;/strong&gt; pois ele já vem empacotado junto com o projeto do Gatsby.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depois de instalar o ESLint em nosso projeto vamos iniciar a configuração através do Wizard. Execute o comando abaixo e responda as perguntas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;$ yarn eslint --init&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;
- How would you like to use ESLint?
&amp;gt; To check syntax, find problems, and enforce code style

- What type of modules does your project use?
&amp;gt; JavaScript modules (import/export)

- Which framework does your project use?
&amp;gt; React

- Does your project use TypeScript?
&amp;gt; No

- Where does your code run?
&amp;gt; Browser

- How would you like to define a style for your project? (Use arrow keys)
&amp;gt; Use a popular style guide ? AirBnb

- What format do you want your config file to be in?
&amp;gt; JavaScript

- Would you like to install them now with npm? (Y/n)
&amp;gt; Y
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;🗒 Ao final do processo eu apago o arquivo &lt;strong&gt;&lt;code&gt;package-lock.json&lt;/code&gt;&lt;/strong&gt; e rodo o comando &lt;strong&gt;&lt;code&gt;yarn install&lt;/code&gt;&lt;/strong&gt; para atualizar o &lt;strong&gt;&lt;code&gt;yarn.lock&lt;/code&gt;&lt;/strong&gt;. Pois o Gatsby utiliza o &lt;strong&gt;&lt;code&gt;yarn&lt;/code&gt;&lt;/strong&gt; como gerenciador de dependências do projeto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depois de terminado o processo será criado um arquivo .eslintrc.js na pasta raiz do nosso projeto, como também será instalado um série de dependências necessárias para o nosso guia de estilo escolhido.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configurando o Prettier
&lt;/h3&gt;

&lt;p&gt;Quando combinamos o ESLint e Prettier podemos enfrentar alguns problemas na formatação do nosso código, por que existem algumas regras comuns entre os pacotes, causando conflitos. Para contornamos essa situação, iremos instalar e configurar um &lt;a href="https://github.com/prettier/eslint-config-prettier"&gt;pacote de configuração do Prettier para ESLint&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Vamos adicionar o seguinte pacote ao projeto que irá desabilitar todas as regras ESLint relacionadas à formatação.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;$ yarn add eslint-config-prettier -D&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ao final do processo edite o arquivo &lt;strong&gt;&lt;code&gt;.eslintrc.json&lt;/code&gt;&lt;/strong&gt; para incluir essa configuração.&lt;/p&gt;

&lt;pre&gt;
{
  "extends": ["airbnb", "prettier", "prettier/react"]
}
&lt;/pre&gt;

&lt;p&gt;Este pacote desabilita todas as regras do ESLint relacionadas à formatação.&lt;/p&gt;

&lt;p&gt;O próximo passo é o pacote é o Plugin Prettier para ESLint. Este plugin faz com que o Prettier seja executado como uma regra ESLint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;$ yarn add  eslint-plugin-prettier -D&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para utilizá-lo, adicione, o código a seguir, no arquivo &lt;strong&gt;&lt;code&gt;.eslintrc.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;
"plugins": [
  "prettier"
],
"rules": {
  "prettier/prettier": "error"
}
&lt;/pre&gt;

&lt;h3&gt;
  
  
  Regras adicionais
&lt;/h3&gt;

&lt;p&gt;Embora a guia de estilo do &lt;strong&gt;&lt;code&gt;Airbnb&lt;/code&gt;&lt;/strong&gt; seja excelente em seu conjunto de regras, faremos um configuração adicional nas regras do ESlint. &lt;/p&gt;

&lt;p&gt;Usaremos a configuração existente no arquivo &lt;strong&gt;&lt;code&gt;.eslintrc.json&lt;/code&gt;&lt;/strong&gt; como ponto de partida e vamos adicionar algumas regras específicas ao Prettier em nossa configuração ESLint.&lt;/p&gt;

&lt;pre&gt;
// .eslintrc.json
module.exports = {
  env: {
    browser: true,
    es6: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'prettier', 'prettier/react'
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
  },
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  plugins: [
    'react',
    'prettier'
  ],
  rules: {
    "prettier/prettier": [
      "error",
      {
          "singleQuote": true,
          "printWidth": 120,
          "trailingComma": "es5"
      } 
    ],
    "react/jsx-filename-extension": [
      1,
      {
          "extensions": [
              ".js",
              ".jsx"
          ]
      }
  ],
  "react/prop-types": 0,
  "no-unused-vars": [
      "error",
      {
          "vars": "local",
          "args": "none"
      }
  ],
  "jsx-a11y/anchor-is-valid": [
      "error",
      {
          "components": [
              "Link"
          ],
          "specialLink": [
              "to",
              "hrefLeft",
              "hrefRight"
          ],
          "aspects": [
              "noHref",
              "invalidHref",
              "preferButton"
          ]
      }
  ]
  },
// Configuração para o Gatsby
  settings: {
    'import/core-modules': [
        "react"
    ]
}
};
&lt;/pre&gt;

&lt;h5&gt;
  
  
  Configuração para o Gatsby
&lt;/h5&gt;

&lt;pre&gt;
  settings: {
    'import/core-modules': [
        "react"
    ]
}
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;Como iniciamos o projeto pelo Gatsby, iremos adicionar o pacote React para que o ESLint não nos avise sobre as importações não existentes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Definindo as configurações do VSCode
&lt;/h3&gt;

&lt;p&gt;Antes de prosseguir, vamos configurar o VSCode para executar o eslint e o prettier sempre que um arquivo for salvo.&lt;/p&gt;

&lt;p&gt;Abra as configurações do usuário (em modo JSON) em pelo menu &lt;strong&gt;&lt;code&gt;[File&amp;gt; Preferences &amp;gt; Settings]&lt;/code&gt;&lt;/strong&gt; ou pelo atalho Ctrl+,.&lt;/p&gt;

&lt;pre&gt;
  // Eslint Prettier
  "editor.formatOnSave": true,
  "[javascript]": {
    "editor.formatOnSave": false,
  },
  "[javascriptreact]": {
    "editor.formatOnSave": false,
  },
  "prettier.disableLanguages": [
    "js"
  ],
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "eslint.alwaysShowStatus": true,
&lt;/pre&gt;

&lt;h4&gt;
  
  
  Explicando por partes:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A entrada &lt;code&gt;editor.formatOnSave&lt;/code&gt; faz com que o VSCode formate o documento sempre que salvar um arquivo.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
  "editor.formatOnSave": true,
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;Desativa explicitamente a formatação para arquivos javascript, pois iremos formatar através do ESLint.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
  "[javascript]": {
    "editor.formatOnSave": false,
  },
  "[javascriptreact]": {
    "editor.formatOnSave": false,
  },
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;Executa o ESLint em cada salvamento (com o sinalizador --fix).&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;Força o ESLint para sempre mostrar seu status na parte inferior do VSCode &lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
  "eslint.alwaysShowStatus": true,
&lt;/pre&gt;

&lt;h3&gt;
  
  
  Considerações
&lt;/h3&gt;

&lt;p&gt;Por fim, configuramos com sucesso o ESLint para trabalhar em conjunto com o Prettier. Agora somos notificados pelo VSCode sobre problemas de lint e sobre problemas de formatação. Sempre que salvarmos um arquivo .js, esses dois pacotes trabalharão juntos em nosso favor e farão um fix de todos os problemas. Bons códigos!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
