<?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: Becomex</title>
    <description>The latest articles on DEV Community by Becomex (@becomex).</description>
    <link>https://dev.to/becomex</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%2Forganization%2Fprofile_image%2F6445%2F8781a784-d46b-407b-b481-423d3d6b8034.jpg</url>
      <title>DEV Community: Becomex</title>
      <link>https://dev.to/becomex</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/becomex"/>
    <language>en</language>
    <item>
      <title>Cursor: um editor de código com IA integrada</title>
      <dc:creator>vandrei de lima</dc:creator>
      <pubDate>Thu, 26 Jun 2025 19:13:22 +0000</pubDate>
      <link>https://dev.to/becomex/cursor-um-editor-de-codigo-com-ia-integrada-5om</link>
      <guid>https://dev.to/becomex/cursor-um-editor-de-codigo-com-ia-integrada-5om</guid>
      <description>&lt;h1&gt;
  
  
  Minha experiência com o Cursor: uma IDE com IA integrada
&lt;/h1&gt;

&lt;p&gt;Com o objetivo de testar uma nova IDE, dediquei duas semanas para estudar e experimentar o &lt;strong&gt;Cursor&lt;/strong&gt;, uma plataforma baseada no Visual Studio Code que se destaca pela sua &lt;strong&gt;integração nativa com inteligência artificial&lt;/strong&gt;. Quis entender seu potencial para aumentar a produtividade e a eficiência no desenvolvimento de software. Durante esse período, utilizei a versão gratuita e a versão Pro em diferentes projetos.&lt;/p&gt;

&lt;p&gt;No processo de desenvolvimento, alguns fatores contribuíram para uma boa performance e agilidade na entrega, como o entendimento completo das bibliotecas e frameworks utilizados, a visão holística do projeto e a compreensão dos requisitos das atividades. Tentei explorar a IDE ao máximo para identificar onde ela poderia facilitar e agilizar o processo de desenvolvimento. Neste artigo, explico primeiro as suas funcionalidades e, posteriormente, minha experiência prática com ela.&lt;/p&gt;




&lt;h2&gt;
  
  
  Primeiras impressões e tutorial inicial
&lt;/h2&gt;

&lt;p&gt;Logo após o primeiro login, a IDE oferece a opção de importar configurações do VS Code — o que facilita bastante para quem já é familiarizado com aquele ambiente. A interface é praticamente idêntica à do VS Code, o que reduz muito a curva de aprendizado.&lt;/p&gt;

&lt;p&gt;A instalação inicial é fluida e já conta com opções como terminal personalizado e sugestões inteligentes ativadas por padrão. Ela tem alguns modos de funcionamento como Agent, Ask e Manual.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent&lt;/strong&gt;: a IDE irá conhecer a sua base de código de forma automática e poderá aplicar alterações em todo o seu código de acordo com as suas necessidades, é a forma mais recomendada de ser utilizada.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ask&lt;/strong&gt;: é a maneira convencional de se utilizar o Chat IA. Você consegue obter explicações e sugestões pelo chat sem que ele aplique alterações no seu código.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manual&lt;/strong&gt;: semelhante ao Agent, porém voltado para um escopo mais específico de alteração. A diferença é que não explora a sua base de código e nem executa comandos no terminal.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A IDE oferece um tutorial direto ao ponto, com atalhos que maximizam a interação com a IA:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl + K&lt;/strong&gt;: interações com o código, como refatorações ou criação de funções.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tab&lt;/strong&gt;: sugestões inteligentes e autocompletar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ctrl + I&lt;/strong&gt;: geração de estruturas como pastas e componentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Além disso, o painel lateral com o chat da IA fornece essas funções de forma interativa. As respostas são rápidas e mostram um entendimento surpreendente das tarefas, muitas vezes antecipando necessidades e oferecendo soluções antes mesmo de serem solicitadas. Claro que descrever o contexto com detalhes importantes ajuda a ter uma resposta mais precisa sobre a necessidade.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recursos notáveis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Autocompletar inteligente
&lt;/h3&gt;

&lt;p&gt;O recurso de autocompletar do Cursor se destaca por sua inteligência contextual avançada. Ao analisar o código existente e a estrutura do projeto, ele oferece sugestões precisas e contextualmente relevantes. A tecla &lt;strong&gt;Tab&lt;/strong&gt; ativa essas sugestões, que vão desde completar funções e variáveis até gerar blocos de código inteiros baseados no padrão do projeto. O sistema aprende com seu estilo de codificação e se adapta, tornando o desenvolvimento mais fluido e eficiente. Infelizmente, na versão gratuita esse recurso tem limitações significativas de uso, o que pode impactar a experiência completa da ferramenta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aprimoramento com contexto
&lt;/h3&gt;

&lt;p&gt;O chat da IDE possui um recurso poderoso de adição de contexto que potencializa significativamente as respostas da IA. Você pode enriquecer suas solicitações de várias formas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Referências de código&lt;/strong&gt;: incluir caminhos relativos de arquivos ou nomes de componentes/páginas específicas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentação&lt;/strong&gt;: anexar documentos técnicos ou especificações.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Referências visuais&lt;/strong&gt;: adicionar imagens ou mockups para implementação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Descrições detalhadas&lt;/strong&gt;: fornecer explicações contextuais sobre o objetivo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quanto mais contexto você fornecer, mais precisas e alinhadas serão as sugestões e implementações geradas pela IA. O sistema é flexível, permitindo tanto referências diretas a arquivos quanto descrições verbais do que precisa ser modificado.&lt;/p&gt;




&lt;h2&gt;
  
  
  Modos de seleção da IA
&lt;/h2&gt;

&lt;p&gt;O Cursor oferece diferentes IAs. Você pode selecioná-las manualmente ou deixar no modo automático e, conforme a sua necessidade, ele avalia qual seria a melhor para te atender.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modo automático&lt;/strong&gt;: ótimo para tarefas rotineiras.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modo MAX&lt;/strong&gt;: gera respostas mais completas e inteligentes, mas consome rapidamente os créditos da licença Pro.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Meus primeiros usos
&lt;/h2&gt;

&lt;p&gt;Utilizei a IA em dois tipos de projetos: o primeiro iremos chamar de Projeto A, e o segundo, de Projeto B. No Projeto A, com uma interface já planejada e pronta no Figma, componentes e bibliotecas já estabelecidas, e regras de autenticação e permissões já definidas, testei a IA em um ambiente mais "engessado" para ver como ela poderia acelerar e melhorar as entregas. No Projeto B, foi um teste em um escopo aberto na criação de SAAS, onde dei mais liberdade e tentei acelerar o desenvolvimento.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Projeto A
&lt;/h3&gt;

&lt;p&gt;Após a criação manual do projeto a partir de um template básico com autenticação e configurações de deploy, iniciei a configuração do meu CSS, pedindo a instalação completa do &lt;strong&gt;Tailwind CSS&lt;/strong&gt;. Após isso, expliquei para ela as páginas que eu utilizaria e, em seu contexto, sempre deixando claro as ferramentas que ela poderia utilizar, como Ant Design. Utilizei prints do Figma para ela inicializar os meus componentes. Nesse ponto, tive muita vantagem na organização do projeto, porém, por serem componentes complexos e customizados do Ant Design, consegui aproveitar cerca de 20% do que ela criou.&lt;/p&gt;

&lt;p&gt;Para um uso eficiente da IA, ao realizar minhas perguntas, eu mencionava brevemente as ferramentas disponíveis no projeto e alguns componentes já criados para que ela utilizasse como exemplo. No chat, existe um campo para adicionar o contexto, que pode ser qualquer coisa, como um texto ou arquivo, mas o que mais utilizei foi inserir o caminho do local onde eu gostaria que ela aplicasse a alteração ou usasse como exemplo. O caminho pode ser passado diretamente no chat ou colocado nas opções de contexto. A IA consegue usar esses caminhos relativos para entender e gerar componentes com base em outros existentes.&lt;/p&gt;

&lt;p&gt;Durante a reorganização de componentes, observei que alguns trechos foram quebrados — o que exigiu correções manuais. O próprio chat permite uma revisão das alterações que poderão ser aprovadas ou rejeitadas, isso facilitou muito a análise das suas implementações.&lt;/p&gt;

&lt;p&gt;No Projeto A, ela se mostrou muito útil em atividades como criar e aplicar a tradução nas labels e campos, melhoria e organização do código, identificação de perda de memória ou problemas no ciclo de vida de execução, e melhoria na resolução de bugs e inconsistências. Seu autocompletar fez uma diferença significativa, não consegui mensurar com precisão, mas tive uma melhoria de 15% na velocidade das entregas apenas com o recurso de autocompletar.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Projeto B
&lt;/h3&gt;

&lt;p&gt;No Projeto B, criei um backend com NestJS apenas explicando o contexto do projeto e com um arquivo da estrutura da base de dados. Ela criou as APIs que solicitei, deixando tudo configurado e até mesmo uma integração com gateway de pagamento, onde tive apenas o trabalho de passar a chave da API. Pedi para que criasse um arquivo de documentação das APIs e dos detalhes de funcionamento. Exportei o chat e usei junto o arquivo de documentação no projeto front já pré-configurado. Pedi para que ela lesse o arquivo de documentação e sozinha criou as implementações de telas para cada API criada no backend, só tive o trabalho de validar o código implementado. Claro que nesse contexto dei a liberdade "artística" na interface e nos componentes. Tive um ganho de tempo super considerável usando-a nesse contexto.&lt;/p&gt;

&lt;p&gt;Em resumo, testei sua capacidade de ler imagens e compreender códigos já implementados, com o objetivo de usá-los como referência para novas criações. Nesse processo, identifiquei algumas limitações, que podem ser atenuadas ao formular perguntas mais claras e direcionadas, além de fornecer links para artigos específicos e exemplos alinhados ao padrão de código existente.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dicas de uso
&lt;/h2&gt;

&lt;p&gt;O seu autocomplete (TAB) é muito poderoso, porém, para a versão gratuita acaba sendo bem limitado. Sugiro analisar bem cada uso para que otimize o que realmente seja vantajoso. Percebo que, em alguns casos, apenas conhecer os atalhos nativos da IDE já seria suficiente. No entanto, sua utilidade se destaca mesmo quando compreende o conceito por trás da lógica e consegue antecipar funções e implementações mais entensas.&lt;/p&gt;

&lt;p&gt;Assim como a maioria das IAs, a forma com que geramos as perguntas melhora a entrega e reduz o gasto das requisições. Esclarecer para ela de forma direta e reduzida melhora bastante a performance das entregas. Aqui vão algumas dicas de como montar as suas perguntas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tarefa: esclarecer diretamente o que precisa ser feito.&lt;/li&gt;
&lt;li&gt;Contexto: dizer brevemente as ferramentas e linguagens que estão sendo utilizadas, ou até o contexto de mercado.&lt;/li&gt;
&lt;li&gt;Output: formato de saída, se seria apenas uma resposta simples ou alteração direta no código.&lt;/li&gt;
&lt;li&gt;Exemplos: passar exemplos do próprio código, ou até mesmo recursos externos como links para aprendizado ou identificação do padrão de desenvolvimento.&lt;/li&gt;
&lt;li&gt;Regras: definir regras para impedir que ela altere pontos críticos ou utilize algum padrão não desejado no desenvolvimento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usando esse padrão, consegui aproveitar melhor os tokens fornecidos gratuitamente e da versão Pro do Cursor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vale a pena a versão Pro?
&lt;/h2&gt;

&lt;p&gt;A versão Pro custa US$20, cerca de R$118 na cotação da compra. Em testes, criei um CRUD do zero, sem especificações detalhadas de UI,e a IA &lt;strong&gt;reduziu em até 80% o esforço bruto&lt;/strong&gt;. E, diferente da versão gratuita, o uso do autocomplete e das respostas mais complexas acaba não sendo tão limitado. Comparando com a versão gratuita, a maior diferença é perceptível no uso do autocomplete. Nas demais funcionalidades, com o modo "Max" também vemos uma compreensão melhor e respostas com uma qualidade superior.&lt;/p&gt;

&lt;p&gt;Na minha experiência, a versão Pro realmente faz diferença para quem busca produtividade máxima e utiliza intensamente recursos de IA no dia a dia. O maior benefício está no desbloqueio do autocompletar inteligente e na liberdade para usar o modo Max sem se preocupar tanto com limites. Para quem trabalha com projetos grandes, precisa de respostas mais completas ou quer acelerar entregas, o investimento se paga rapidamente. No entanto, para usos mais pontuais ou para quem está começando, a versão gratuita já oferece um bom panorama das capacidades da ferramenta, permitindo avaliar se vale a pena migrar para o plano pago.&lt;/p&gt;




&lt;h2&gt;
  
  
  Nem tudo são flores
&lt;/h2&gt;

&lt;p&gt;Apesar dos muitos pontos positivos, a ferramenta pode apresentar oscilações consideráveis na qualidade das entregas. Em alguns momentos, ela altera arquivos por conta própria, toma decisões inesperadas e até remove funcionalidades importantes, o que pode ser frustrante. No entanto, esses casos não são tão frequentes e, na maioria das vezes, o resultado é satisfatório. É importante sempre revisar as alterações sugeridas pela IA antes de aprová-las, garantindo que nada essencial seja perdido ou modificado indevidamente.&lt;/p&gt;




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

&lt;p&gt;O Cursor se mostrou uma ferramenta poderosa para desenvolvedores que querem aliar produtividade e inteligência artificial no fluxo de trabalho. Sua integração nativa com IA, somada à interface familiar do VS Code, torna a adoção fácil e o ganho de eficiência perceptível desde os primeiros usos. O autocompletar inteligente, o chat contextual e a possibilidade de aplicar alterações diretamente no código são diferenciais que realmente impactam o dia a dia.&lt;/p&gt;

&lt;p&gt;Apesar de algumas limitações na versão gratuita, principalmente no uso do autocompletar, a experiência geral é muito positiva. A versão Pro potencializa ainda mais esses ganhos, sendo indicada para quem deseja extrair o máximo da ferramenta. O segredo para aproveitar bem está em saber formular perguntas objetivas, fornecer contexto e explorar os recursos de automação oferecidos.&lt;/p&gt;

&lt;p&gt;Recomendo o Cursor para quem já tem um bom conhecimento em programação, seja em projetos pessoais ou profissionais, e quer experimentar o futuro das IDEs com IA integrada. Não recomendo para iniciantes na programação, pois ele poderia até prejudicar seus conhecimentos caso seja usado de maneira inadequada no aprendizado.&lt;/p&gt;




&lt;p&gt;🔗 &lt;a href="https://www.cursor.so/" rel="noopener noreferrer"&gt;Site oficial do Cursor&lt;/a&gt;  &lt;/p&gt;

</description>
    </item>
    <item>
      <title>gRPC: um panorama do contexto histórico às aplicações práticas!</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Sun, 20 Oct 2024 18:36:29 +0000</pubDate>
      <link>https://dev.to/becomex/grpc-um-panorama-do-contexto-historico-as-aplicacoes-praticas-4j2l</link>
      <guid>https://dev.to/becomex/grpc-um-panorama-do-contexto-historico-as-aplicacoes-praticas-4j2l</guid>
      <description>&lt;p&gt;Olá, pessoal. Tudo bem?&lt;/p&gt;

&lt;p&gt;Há algum tempo, desenvolvi um conteúdo sobre gRPC para criar um bootcamp e disseminar este conhecimento entre os times de software da Becomex. Embora o modelo de bootcamp não tenha sido implementado na prática, o material ficou excelente. Por isso, decidi transformar a parte teórica em um post e compartilhar esse conteúdo com a comunidade.&lt;/p&gt;

&lt;p&gt;Para aprender qualquer coisa na vida, começar pelo básico é sempre uma ótima ideia. Antes de mergulharmos no gRPC, vamos entender o que é RPC e o caminho que nos trouxe até aqui. Neste artigo, você terá uma breve introdução aos conceitos de RPC, a diferença básica entre RPC e REST, e entenderá por que o gRPC é tão rápido e uma excelente alternativa para a transição de grandes volumes de dados. Além disso, vamos apresentar exemplos de implementação para facilitar o entendimento.&lt;br&gt;
Então, ajeite-se na cadeira e prepare sua garrafa d'água, porque vem muita informação boa por aí!&lt;/p&gt;
&lt;h2&gt;
  
  
  A origem
&lt;/h2&gt;

&lt;p&gt;O RPC ou &lt;em&gt;Remote Procedure Call&lt;/em&gt; (chamada de processo remoto em português) é uma técnica que permite realizar a chamada de uma função de forma remota. Com o RPC, o recurso &lt;strong&gt;A&lt;/strong&gt; solicita a execução de uma função ao recurso &lt;strong&gt;B&lt;/strong&gt;, estes podem ser componentes distintos que compõem um grande circuito, ou computadores conectados em rede, mostrando que esse modelo de comunicação não está vinculado somente ao protocolo HTTP, mas também se aplicando facilmente a outros protocolos de comunicação.&lt;/p&gt;

&lt;p&gt;As proposições teóricas de modelos de chamadas remotas em redes de computadores começaram a ser feitas na década de 70, tendo como marco importante a publicação da &lt;a href="https://www.rfc-editor.org/rfc/rfc707" rel="noopener noreferrer"&gt;RFC 707&lt;/a&gt; no final do ano de 1975 e no começo do ano de 1976 sob o título &lt;em&gt;A High-Level Framework for Network-Based Resource Sharing&lt;/em&gt;. Esse documento, dentre outras coisas, enfatizou a necessidade de padronização dos protocolos de comunicação entre sistemas.&lt;/p&gt;

&lt;p&gt;O primeiro uso comercial do modelo de comunicação RPC ocorreu em um projeto desenvolvido pela Xerox PARC em 1981. Foi durante esse período que o termo RPC teria sido cunhado por Bruce Jay Nelson, um dos cientistas da computação da empresa.&lt;/p&gt;

&lt;p&gt;Anos mais tarde, o Google criou sua própria arquitetura RPC. Essa infraestrutura de propósito geral chamada Stubby foi utilizada por mais de uma década para conectar o vasto número de microsserviços operando dentro e entre seus data centers. Como afirmado pela própria Google, o Stubby possuía vários recursos excelentes, mas estava altamente acoplado à sua infraestrutura interna para ser considerado adequado para o lançamento ao público. Em 2015, a Google publica então o gRPC, um projeto de código aberto que nasce como a evolução do Stubby.&lt;/p&gt;

&lt;p&gt;Ao contrário do que muitas pessoas podem pensar, o "g" em gRPC não significa Google. Na realidade, a cada nova versão lançada do gRPC, o "g" é ressignificado. &lt;a href="https://github.com/grpc/grpc/blob/master/doc/g_stands_for.md?ref=blog.lsantos.dev" rel="noopener noreferrer"&gt;Clique aqui&lt;/a&gt; e confira a lista de nomes atribuídos ao “g”. Para todos os efeitos, podemos entender o termo gRPC como &lt;em&gt;high performance Remote Procedure Call&lt;/em&gt; ou chamada de processo remoto de alta performance no nosso bom português.&lt;/p&gt;
&lt;h2&gt;
  
  
  Diferença entre RPC e REST
&lt;/h2&gt;

&lt;p&gt;O modelo REST &lt;em&gt;Representational State Transfer&lt;/em&gt; é potencialmente o mais popular atualmente, e a maioria das APIs web com que trabalhamos são REST ou pseudo REST. Por isso, parece ser uma boa ideia explicar como o RPC funciona comparando-o a um modelo mais conhecido.&lt;/p&gt;

&lt;p&gt;Fundamentalmente, o REST expõe os recursos ou entidades de sua aplicação e usa os métodos HTTP para fornecer significado semântico às ações realizadas. Já o RPC expõe as operações que a aplicação pode realizar e, em geral, usa apenas dois diferentes métodos HTTP (quando a comunicação se dá por esse protocolo).&lt;/p&gt;

&lt;p&gt;Em uma API REST, se você desejar expor dados sobre usuários, você provavelmente teria o seguinte cenário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET api/v1/users
GET api/v1/users/:id
POST api/v1/users
PUT api/v1/users/:id
DELETE api/v1/users/:id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em uma API RPC, ao invés de expor uma rota de usuários e usar os métodos HTTP para atribuir significado às operações, cada rota se parecerá como uma função específica. Veja o exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET api/v1/getUserList
GET api/v1/getUserById
POST api/v1/createUser
POST api/v1/updateUser
POST api/v1/deleteUser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada modelo de comunicação oferece diferentes níveis de facilidade para representar as operações de uma aplicação. O REST, por exemplo, é ideal para operações de CRUD (criar, ler, atualizar, deletar), enquanto o RPC é mais eficiente para executar ações da sua aplicação, como enviar e-mails ou realizar cálculos. No entanto, nada impede que o RPC seja usado para operações de CRUD, assim como o REST pode ser aplicado para executar funções em uma API.&lt;/p&gt;

&lt;h2&gt;
  
  
  De onde vem o &lt;em&gt;high performance&lt;/em&gt; do gRPC?
&lt;/h2&gt;

&lt;p&gt;A essa altura, você já deve ter percebido que o gRPC nada mais é do que a implementação de um modelo de API RPC, construído de modo a fornecer um alto desempenho em suas execuções. Mas como esse alto desempenho é construído? A primeira coisa que precisamos entender é que o gRPC não é uma tecnologia em si, mas uma junção de várias técnicas e tecnologias. Bora explorar cada uma delas?&lt;/p&gt;

&lt;h3&gt;
  
  
  Execução sob o protocolo de comunicação HTTP/2
&lt;/h3&gt;

&lt;p&gt;Implementar uma API gRPC significa utilizar o protocolo HTTP/2 para estabelecer a conexão e a troca de informação entre o cliente e o servidor. O HTTP/2 que também foi criado pelo Google oferece vários recursos de melhoria de desempenho em relação ao seu antecessor. Aqui, vamos explorar duas de suas principais características, mas você pode ter uma leitura completa consultando a &lt;a href="https://www.rfc-editor.org/rfc/rfc7540" rel="noopener noreferrer"&gt;RFC 7540&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Stream e Multiplexação
&lt;/h4&gt;

&lt;p&gt;Uma das principais limitações do HTTP/1.1 é a sua restrição no envio e recebimento de dados. Nesta versão, não é possível enviar ou receber mais de uma mensagem por conexão, o que significa que, se você precisar enviar duas mensagens ao servidor, terá que abrir duas conexões separadas. Isso torna o processo mais lento, já que a cada requisição é necessário refazer o &lt;em&gt;handshake&lt;/em&gt; com o servidor e reenviar eventuais informações repetitivas entre as requisições. Além disso, por questões de desempenho, o número de conexões simultâneas que um browser pode fazer com um servidor é limitado. Para entender melhor essa limitação, recomendo o artigo &lt;a href="https://ishwar-rimal.medium.com/why-does-your-browser-limit-the-number-of-concurrent-network-calls-1ae5d50863dd" rel="noopener noreferrer"&gt;Why does your browser limit the number of concurrent network calls?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O protocolo HTTP/2, por outro lado, permite algo chamado multiplexação, o que significa que é possível enviar mais de uma requisição ao servidor por meio de uma única conexão. Isso resolve as limitações de conexões simultâneas e os tempos de &lt;em&gt;handshake&lt;/em&gt; que a versão anterior impunha. A imagem abaixo, retirada do livro &lt;em&gt;HTTP/2 in Action&lt;/em&gt;, ilustra de forma simples esse funcionamento.&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%2Fzz993u6zxr6qmaepuoqe.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%2Fzz993u6zxr6qmaepuoqe.png" alt="Comparação entre http/1.1 e http/2" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Compressão e redução dos headers
&lt;/h4&gt;

&lt;p&gt;Outra característica interessante do HTTP/2 é a compressão dos &lt;em&gt;headers&lt;/em&gt; das mensagens. Em alguns casos, os &lt;em&gt;headers&lt;/em&gt; de uma requisição podem ser maiores que o próprio &lt;em&gt;payload&lt;/em&gt;, e o HTTP/2 faz uma compressão eficiente dessas informações. Além disso, como essa versão mantém uma única conexão para várias solicitações, não é necessário reenviar todos os &lt;em&gt;headers&lt;/em&gt; em cada requisição. O HTTP/2 apenas retransmite os &lt;em&gt;headers&lt;/em&gt; que foram alterados e, para os que permanecem iguais, envia apenas um índice de referência.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protocol Buffers
&lt;/h3&gt;

&lt;p&gt;O Protocol Buffers (ou Protobuf, para os íntimos) é um método muito eficiente de serialização de dados. O Protobuf usa uma linguagem de definição de interface (IDL) para descrever arquivos agnósticos de plataformas e linguagens de programação. Esses arquivos contêm as especificações dos contratos e funções que o servidor pode fornecer e tanto o cliente quanto o servidor mantêm uma cópia desses arquivos, o que garante a coesão na troca de informações. Além disso, isso separa o contexto das mensagens trocadas na rede do seu conteúdo, diferentemente de contratos em JSON, onde contexto e conteúdo são enviados necessariamente juntos.&lt;/p&gt;

&lt;p&gt;Veja o exemplo abaixo, que utiliza a IDL do Protobuf para descrever um contrato de um objeto que representa um produto, com as propriedades &lt;em&gt;partnumber&lt;/em&gt;, que significam o código e a quantidade de um produto:&lt;br&gt;
&lt;/p&gt;

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

message Produto {
  string partnumber = 1;
  int32 quantidade = 2;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na primeira linha, definimos a sintaxe "proto3". Na terceira, declaramos uma mensagem (ou objeto) chamada "Produto", que pode ser usada tanto como entrada quanto saída de uma função. As linhas quatro e cinco definem as propriedades desse objeto, indicando o tipo, nome e índice de cada uma. E aqui está o interessante: nós definimos índices que determinam a posição das propriedades, o que significa que a mensagem enviada via gRPC não precisa carregar o nome da propriedade, apenas seu índice.&lt;/p&gt;

&lt;p&gt;Para ilustrar de forma mais clara, veja o exemplo em JSON que seria necessário para representar essa mensagem:&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;"partnumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Boinas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;150&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;Cada caractere da mensagem acima precisa ser transmitido pela rede por meio físico do servidor até o cliente. Quanto maior a mensagem, mais tempo levará para ser transmitida. O Protobuf codifica essa mesma mensagem em um conjunto muito menor de dados, o que acelera a transmissão pela rede. A codificação dessa mensagem pelo Protobuf seria a seguinte: &lt;code&gt;0A06426F696E6173109601&lt;/code&gt;. Não se preocupe, vou explicar como chegamos a esse valor em breve 😉. E ainda, graças ao HTTP/2, esses dados serão comprimidos antes de serem transmitidos.&lt;/p&gt;

&lt;p&gt;O Protobuf, que também foi criado pelo Google, pode ser usado de forma independente, sem estar necessariamente no contexto do gRPC. Se salvarmos o exemplo anterior em um arquivo chamado &lt;code&gt;Produto.proto&lt;/code&gt;, podemos rodar o seguinte comando no terminal: &lt;code&gt;echo 'partnumber: "boinas"; quantidade: 150' | protoc --encode=Produto produto.proto &amp;gt; produto.bin&lt;/code&gt; (você precisará instalar o &lt;a href="https://grpc.io/docs/protoc-installation/?ref=blog.lsantos.dev" rel="noopener noreferrer"&gt;protoc&lt;/a&gt; para isso). O comando &lt;code&gt;echo&lt;/code&gt; indica que queremos imprimir um conteúdo, o texto entre aspas simples é o conteúdo que queremos imprimir, concatenamos essa impressão com a chamada do &lt;code&gt;protoc&lt;/code&gt; indicando que queremos fazer o encode do objeto "Produto" &lt;code&gt;--encode=Produto&lt;/code&gt; especificado dentro do arquivo &lt;code&gt;produto.proto&lt;/code&gt;, por fim definimos que o resultado deve ser salvo dentro do arquivo &lt;code&gt;produto.bin&lt;/code&gt;. Para visualizar arquivos com essa codificação, gosto de usar o VS Code com a extensão &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.hexeditor" rel="noopener noreferrer"&gt;Hex Editor&lt;/a&gt;. É assim que você verá a sequência de caracteres &lt;code&gt;0A06426F696E6173109601&lt;/code&gt; mencionada anteriormente.&lt;/p&gt;

&lt;p&gt;O resultado gerado por essa operação é uma sequência hexadecimal, onde cada par de caracteres representa um conjunto de 8 bits. Vamos dar uma olhada mais detalhada nessa estrutura.&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%2Fb1usyz0oxszed1l5nb8p.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%2Fb1usyz0oxszed1l5nb8p.png" alt="Decomposição da sequência hexadecimal" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O primeiro bit de cada par é o &lt;em&gt;most significant bit&lt;/em&gt; (MSB), ou continuation bit. Essa é uma estratégia inteligente de codificação para indicar se o próximo par faz parte da mesma representação de dado ou se é um dado separado. Quando o valor é 0, o par contém toda a informação. Se for 1, é necessário combinar os bits com o próximo par para interpretar o dado.&lt;/p&gt;

&lt;p&gt;Os pares &lt;strong&gt;0A&lt;/strong&gt; e &lt;strong&gt;10&lt;/strong&gt;, destacados em vermelho na imagem, representam as definições das propriedades enviadas. Após o primeiro bit (MSB), os próximos 4 bits indicam o índice da propriedade (lembrando que no arquivo .proto definimos índices representados aqui), e os três bits seguintes destacados em negrito indicam o tipo da mensagem.&lt;/p&gt;

&lt;p&gt;O par &lt;strong&gt;06&lt;/strong&gt;, destacado em azul, indica o comprimento da mensagem de texto (neste caso, 6 conjuntos), sempre que o tipo do dado for uma string, o dado será precedido por um ou mais conjuntos que definem o comprimento do texto transmitido na propriedade. Em seguida, destacado em cinza, temos a mensagem "Boinas", codificada.&lt;/p&gt;

&lt;p&gt;Os últimos dois conjuntos, &lt;strong&gt;96&lt;/strong&gt; e &lt;strong&gt;01&lt;/strong&gt;, representam o valor da propriedade "quantidade". Sabemos que devemos interpretar os dois pares juntos porque o primeiro par, &lt;strong&gt;96&lt;/strong&gt;, possui o valor 1 no MSB. Para interpretar um valor numérico serializado pelo Protobuf, removemos o MSB da sequência e aplicamos a técnica &lt;em&gt;little-endian&lt;/em&gt;, ordenando os bits menos significativos à frente. Isso resulta na sequência &lt;em&gt;10010110&lt;/em&gt;, que representa o valor 150 que informamos em nossa mensagem de teste.&lt;/p&gt;

&lt;p&gt;Se quiser entender mais sobre o processo de codificação do Protobuf, você pode consultar as especificações &lt;a href="https://protobuf.dev/programming-guides/encoding/" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sintaxe e tipos padrões
&lt;/h4&gt;

&lt;p&gt;Já vimos um pouco da sintaxe da IDL do Protobuf nos exemplos anteriores, mas vamos nos aprofundar em alguns conceitos básicos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;DocumentoService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;rpc&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;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ListDocumentoRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;reserved&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="na"&gt;analise_id&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;optional&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;tipo_documento&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;optional&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;cnpj_participante&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ListDocumentoResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Documento&lt;/span&gt; &lt;span class="na"&gt;documento&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="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Documento&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="na"&gt;documentoId&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="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;chave_eletronica&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="na"&gt;valido&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="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;cnpj_emitente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;repeated&lt;/span&gt; &lt;span class="na"&gt;Produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;partnumber&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;doubel&lt;/span&gt; &lt;span class="na"&gt;valor&lt;/span&gt; &lt;span class="o"&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;No exemplo acima, usamos o termo service para indicar que estamos descrevendo as funções de um serviço chamado &lt;code&gt;DocumentoService&lt;/code&gt;. Em seguida, usamos o termo &lt;code&gt;rpc&lt;/code&gt; para descrever as funções que esse serviço suporta. Definimos uma função chamada &lt;code&gt;List&lt;/code&gt;, que recebe um objeto &lt;code&gt;ListDocumentoRequest&lt;/code&gt; e retorna um &lt;em&gt;stream&lt;/em&gt; de dados chamado &lt;code&gt;ListDocumentoResponse&lt;/code&gt;. O uso de &lt;em&gt;stream&lt;/em&gt; indica que o volume de dados pode ser alto, permitindo que o cliente processe os dados de forma parcial conforme o servidor os envia.&lt;/p&gt;

&lt;p&gt;Nosso exemplo continua com a definição da estrutura do objeto &lt;code&gt;ListDocumentoRequest&lt;/code&gt;. Nele, especificamos que a posição de índice 3 é &lt;code&gt;reserved&lt;/code&gt;, o que significa que nenhuma propriedade pode ocupar essa posição. A posição 3 não tem nada de especial, foi apenas uma escolha para demonstrar essa possibilidade. Também definimos uma propriedade chamada &lt;code&gt;analise_id&lt;/code&gt; como &lt;code&gt;int64&lt;/code&gt;, e as duas propriedades seguintes são marcadas com o termo &lt;code&gt;optional&lt;/code&gt;. Isso significa que, ao transmitir a mensagem, podemos omitir esses dois parâmetros.&lt;/p&gt;

&lt;p&gt;Um ponto importante a se observar ao definir propriedades como &lt;code&gt;optional&lt;/code&gt; no Protobuf é que, ao fazer isso, habilitamos uma propriedade chamada &lt;code&gt;Has{MinhaVariável}&lt;/code&gt; no objeto convertido para a nossa linguagem de programação. Antes de acessar a propriedade &lt;code&gt;optional&lt;/code&gt;, é essencial verificar se essa propriedade está marcada como &lt;code&gt;true&lt;/code&gt; ou &lt;code&gt;false&lt;/code&gt;. Se tentarmos recuperar a propriedade diretamente, sem essa verificação, receberemos o valor padrão do tipo de dado em questão (0 para inteiros e vazio para strings por exemplo).&lt;/p&gt;

&lt;p&gt;Veja um exemplo em C# de como recuperar esses dados:&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="n"&gt;DocumentoFilter&lt;/span&gt; &lt;span class="nf"&gt;MapToFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt; &lt;span class="n"&gt;request&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;new&lt;/span&gt; &lt;span class="nf"&gt;DocumentoFilter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnaliseId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnaliseId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;TipoDocumento&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasTipoDocumento&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TipoDocumento&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="n"&gt;CnpjParticipante&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CnpjParticipante&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;Antes de acessar o parâmetro &lt;code&gt;TipoDocumento&lt;/code&gt;, foi necessário verificar o estado da propriedade &lt;code&gt;HasTipoDocumento&lt;/code&gt;. Se tivéssemos acessado &lt;code&gt;TipoDocumento&lt;/code&gt; diretamente, o valor retornado seria zero. No caso de &lt;code&gt;CnpjParticipante&lt;/code&gt;, podemos recuperar o valor diretamente, mesmo que seja opcional. Fazer isso não causará erro, o retorno será apenas uma string vazia. Se você precisar diferenciar entre strings vazias e valores nulos (quando o usuário não fornecer esse dado), deverá usar a propriedade &lt;code&gt;HasCnpjParticipante&lt;/code&gt;, da mesma forma como fizemos com &lt;code&gt;TipoDocumento&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Seguindo com a análise da sintaxe do arquivo .proto, temos a definição do objeto &lt;code&gt;ListDocumentoResponse&lt;/code&gt;. Nesse objeto, há uma propriedade do tipo &lt;code&gt;Documento&lt;/code&gt;, que é um objeto personalizado. No Protobuf, podemos encadear objetos livremente, e &lt;code&gt;Documento&lt;/code&gt; possui uma propriedade do tipo &lt;code&gt;Produto&lt;/code&gt; como exemplo. O termo &lt;code&gt;repeated&lt;/code&gt; que precede o tipo &lt;code&gt;Produto&lt;/code&gt; indica que essa propriedade é, na verdade, uma lista de produtos. Você pode consultar os tipos padrões e termos reservados da IDL do Protobuf &lt;a href="https://protobuf.dev/programming-guides/proto3/#scalar" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Um ponto importante a se observar quando estiver criando seus objetos. Caso sua entidade possua uma propriedade &lt;code&gt;repeat&lt;/code&gt; que pode receber uma lista muito grande dados, convêm não inclui-la no retorno de sua entidade, ao invés disso, crie uma outra função que retorne essa lista e permita que seu cliente chame simultaneamente as rotas da entidade pai e de sua lista de propriedades, dessa forma o desempenho na operação dos serviços do gRPC será muito superior.&lt;/p&gt;

&lt;p&gt;Também é possível criar enumeradores no Protobuf e passar parâmetros que aceitam valores nulos, o que elimina a necessidade do termo &lt;code&gt;optional&lt;/code&gt;. Se quiser saber mais sobre isso, você pode consultar a &lt;a href="https://protobuf.dev/reference/protobuf/google.protobuf/" rel="noopener noreferrer"&gt;documentação&lt;/a&gt;. Um conselho: se usar propriedades complexas que podem transmitir valores nulos, não use o termo &lt;code&gt;optional&lt;/code&gt;, já que não faz sentido declarar &lt;code&gt;optional&lt;/code&gt; em propriedades com tipos &lt;em&gt;nullables&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando serviços gRPC
&lt;/h2&gt;

&lt;p&gt;Finalmente chegamos à parte mais esperada: colocar a mão na massa! Para iniciar um projeto de servidor gRPC em C#, você pode usar o seguinte comando: &lt;code&gt;dotnet new grpc -o NomeDoProjeto&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O resultado será um &lt;code&gt;Program&lt;/code&gt; semelhante ao seguinte:&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;using&lt;/span&gt; &lt;span class="nn"&gt;GrpcDocumento.Services&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;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&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="c1"&gt;// Add services to the container.&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddGrpc&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;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Configure the HTTP request pipeline.&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapGrpcService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GreeterService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&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="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A função &lt;code&gt;MapGrpcService&lt;/code&gt; inclui os arquivos de Services que você criar, fornecendo os endpoints definidos nos arquivos .proto. Para começar, basta criar seus próprios arquivos .proto e compilar o projeto. O .NET gerará as classes e tipos necessários para que seu serviço herde a classe base gerada pela compilação do arquivo .proto. Um exemplo disso pode ser visto no template, onde o serviço &lt;code&gt;GreeterService&lt;/code&gt; herda as implementações de &lt;code&gt;Greeter.GreeterBase&lt;/code&gt; e implementa os métodos definidos para o RPC.&lt;/p&gt;

&lt;p&gt;Com o conteúdo que vimos até agora, você já deve ser capaz de criar APIs gRPC simples. Então, vou pular para algo mais avançado e divertido: a criação de métodos que recebem e enviam &lt;em&gt;streams&lt;/em&gt; de dados. Se você precisar de um passo a passo mais detalhado para a criação de servidores gRPC, pode acessar o tutorial: &lt;a href="https://learn.microsoft.com/pt-br/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-8.0&amp;amp;tabs=visual-studio" rel="noopener noreferrer"&gt;Criar um cliente e um servidor gRPC no ASP.NET Core&lt;/a&gt; disponibilizado pela Microsoft.&lt;/p&gt;

&lt;p&gt;Vamos supor que você precise criar uma função que receba e envie um &lt;em&gt;stream&lt;/em&gt; de dados. Um exemplo de implementação seria o seguinte:&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;async&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;IAsyncStreamReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;requestStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;IServerStreamWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;responseStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ServerCallContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while&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;requestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MoveNext&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;filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;MapToFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&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;documentoList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_documentoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDocumentoList&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="k"&gt;await&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;documento&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;documentoList&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;responseStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documento&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;Quando o arquivo .proto define a entrada de dados como &lt;em&gt;stream&lt;/em&gt;, o tipo recebido na função será &lt;code&gt;IAsyncStreamReader&amp;lt;T&amp;gt;&lt;/code&gt;, onde &lt;code&gt;T&lt;/code&gt; é o tipo de dado de entrada. Se o retorno da função for definido como stream, o tipo retornado será &lt;code&gt;IServerStreamWriter&amp;lt;T&amp;gt;&lt;/code&gt;. No &lt;code&gt;requestStream&lt;/code&gt;, você pode usar a função &lt;code&gt;MoveNext&lt;/code&gt; para aguardar o próximo pacote de dados enviado pelo cliente ou processar o pacote já recebido. No &lt;code&gt;responseStream&lt;/code&gt;, você pode usar a função &lt;code&gt;WriteAsync&lt;/code&gt; para enviar pacotes de resposta ao cliente.&lt;/p&gt;

&lt;p&gt;Se você está lidando com &lt;em&gt;streams&lt;/em&gt;, provavelmente trabalhará com grandes volumes de dados. Nesse caso, é interessante realizar consultas paginadas no banco de dados, para otimizar a eficiência e reduzir o volume de dados em trânsito. Confira abaixo um exemplo de implementação para a função &lt;code&gt;GetDocumentoList&lt;/code&gt; usada no exemplo anterior:&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;async&lt;/span&gt; &lt;span class="n"&gt;IAsyncEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetDocumentoList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DocumentoFilter&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;documentoQuery&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDocumentoQueryByFilter&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="nf"&gt;AsNoTracking&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;skip&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;count&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="k"&gt;do&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="m"&gt;0&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;documento&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;documentoQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&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="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;MapToResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;skip&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&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="m"&gt;1000&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 código acima realiza consultas paginadas de 1000 em 1000 registros e processa os dados sob demanda, usando &lt;code&gt;IAsyncEnumerable&lt;/code&gt; e &lt;code&gt;yield return&lt;/code&gt; até que todos os dados compatíveis filtrados sejam retornados.&lt;/p&gt;

&lt;p&gt;Um destaque importante ao criar servidores gRPC que retornam &lt;em&gt;streams&lt;/em&gt; de dados é que os dados enviados para o &lt;em&gt;client&lt;/em&gt; são armazenados em um buffer. Como esse buffer não é infinito, se você enviar dados mais rápido do que o &lt;em&gt;client&lt;/em&gt; pode consumir, poderão ocorrer erros de estouro de buffer. Você pode ignorar esse problema e deixar que o &lt;em&gt;client&lt;/em&gt; lide com o processamento, ou pode ser uma pessoa legal e implementar técnicas que evitem isso, como aguardar um sinal do &lt;em&gt;client&lt;/em&gt; para enviar dados paginados sob demanda, de acordo com sua capacidade de processamento.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consumindo uma API gRPC
&lt;/h3&gt;

&lt;p&gt;Agora, suponha que você já tenha um projeto e deseja consumir uma API gRPC. O processo é bem simples. Primeiro, instale as seguintes bibliotecas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grpc.Net.Client&lt;/li&gt;
&lt;li&gt;Google.Protobuf&lt;/li&gt;
&lt;li&gt;Grpc.Tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em seguida, adicione o código necessário no arquivo &lt;code&gt;csproj&lt;/code&gt; para mapear os arquivos .proto desejados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;Protobut Includ="Protos\documento.proto" GrpcServices="Client" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para saber mais sobre as estruturas e relacionamentos entre os &lt;em&gt;nugets&lt;/em&gt; do gRPC e sua arquitetura, consulte o &lt;a href="https://grpc.io/blog/grpc-on-dotnetcore/" rel="noopener noreferrer"&gt;blog gRPC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Agora vamos implementar a função que cria a conexão com o servidor e chama o &lt;em&gt;endpoint&lt;/em&gt; RPC&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;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;CallDocumentoServiceAsync&lt;/span&gt;&lt;span class="p"&gt;(&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;analiseIdList&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;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GrpcChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ForAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"endereco_grpc"&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;client&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;DocumentoServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&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;duplexStream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;SendRequestMessageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analiseIdList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ReceiveResponseMessageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duplexStream&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="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendRequestMessage&lt;/span&gt;&lt;span class="p"&gt;(&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;analiseIdList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;AsyncDuplexStreamingCall&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;duplexStream&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;analiseId&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;analiseIdList&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;grpcRequest&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;ListDocumentoRequest&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;AnaliseId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;analiseId&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;duplexStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcRequest&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;duplexStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CompleteAsync&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;ReceiveResponseMessageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;AsyncDuplexStreamingCall&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while&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;duplexStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Sua implementação&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 função acima cria um canal gRPC com o endereço do servidor especificado e usa o tipo &lt;code&gt;DocumentoServiceClient&lt;/code&gt; gerado a partir da compilação do arquivo .proto para definir o serviço que será chamado. Em seguida, chamamos a função RPC &lt;code&gt;List&lt;/code&gt;, que recebe e envia um &lt;em&gt;stream&lt;/em&gt; de dados. O retorno da função é um &lt;em&gt;duplexStream&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Em seguida, na função &lt;code&gt;SendRequestMessage&lt;/code&gt;, fazemos o &lt;em&gt;stream&lt;/em&gt; das requisições, escrevendo cada solicitação com &lt;code&gt;await duplexStream.RequestStream.WriteAsync(grpcRequest);&lt;/code&gt;. Depois de enviar todos os pacotes, necessários, é importante informar ao servidor que finalizamos as requisições, chamando a função &lt;code&gt;await duplexStream.RequestStream.CompleteAsync();&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por fim, a função &lt;code&gt;ReceiveResponseMessageAsync&lt;/code&gt; lida com o &lt;em&gt;stream&lt;/em&gt; de retorno do servidor, percorrendo cada um dos retornos com &lt;code&gt;duplexStream.ResponseStream.MoveNext()&lt;/code&gt; para processar os objetos retornados.&lt;/p&gt;

&lt;p&gt;No exemplo fornecido, estamos enviando todas as requisições e, em seguida, recebendo todos os retornos. No entanto, a conexão gRPC é bidirecional, permitindo enviar e receber dados simultaneamente. Isso significa que poderíamos colocar cada função em uma thread separada, otimizando ainda mais o desempenho do envio e recebimento de dados entre cliente e servidor.&lt;/p&gt;

&lt;p&gt;Caso você queira construir um servidor gRPC mas não queira criar um cliente apenas para testes, é possível usar o postman para consumir APIs gRPC, facilitando o teste das suas funções.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão e referências adicionais
&lt;/h2&gt;

&lt;p&gt;O gRPC é uma ferramenta incrível para trafegar grandes volumes de dados, e há muitos cenários onde ele pode ser aplicado. Tenho certeza de que você poderá tirar grande proveito desse conhecimento.&lt;/p&gt;

&lt;p&gt;Abaixo estão alguns links adicionais que você pode gostar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.lsantos.dev/guia-grpc-1/" rel="noopener noreferrer"&gt;https://blog.lsantos.dev/guia-grpc-1/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.hipsters.tech/http2-magia-com-o-novo-protocolo/" rel="noopener noreferrer"&gt;https://www.hipsters.tech/http2-magia-com-o-novo-protocolo/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Sua lógica, sua história: O que seu código diz sobre você</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Mon, 08 Jan 2024 13:42:44 +0000</pubDate>
      <link>https://dev.to/becomex/sua-logica-sua-historia-o-que-seu-codigo-diz-sobre-voce-lld</link>
      <guid>https://dev.to/becomex/sua-logica-sua-historia-o-que-seu-codigo-diz-sobre-voce-lld</guid>
      <description>&lt;p&gt;Olá, pessoal! Espero encontrar todos bem. Hoje você aprenderá que tipo de programador você é, qual é a história que os códigos que você escreve contam sobre você, e em qual gênero literário você seria encaixado se estivesse escrevendo um livro.&lt;/p&gt;

&lt;p&gt;Escrever códigos de computadores é como escrever um livro, algumas estórias nos prendem, nos fazem querer saber mais sobre aquilo que está sendo contato, outras estórias nos repelem, e o único motivo para seguirmos lendo é a obrigação de saber o que acontece no final do livro, digo, final do código. Assim como escritores famosos, nós programadores temos cada um o seu próprio estilo, os seus próprios vícios, e marcamos nossas obras com nossa impressão digital ainda que não percebamos, e ainda que sigamos algum &lt;em&gt;style guide&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As impressões digitais que deixamos para trás ao escrever um código de computador contam muito sobre nós mesmos, e mais ainda, a depender do nosso estilo, diria que nos permitem ser encaixados como produtores literários de livros que vão desde gêneros de romance, até gêneros de terror....&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%2F9ovyp4pvv3zc9nu9r7el.jpg" 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%2F9ovyp4pvv3zc9nu9r7el.jpg" alt="Famosa imagem de mulher gritando ao chuveiro do filme de hitchcock" width="650" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Há algum tempo, eu tive contato com um vídeo sobre React e ficção (link nas referências), no qual a palestrante traça um paralelo entre a escrita criativa de estórias de ficção, e a escrita de códigos de computadores. Inspirado por esse conteúdo, resolvi escrever esse artigo, e nele trato de forma ilusória as minhas próprias percepções sobre os códigos que leio, comparando-os com os sentimentos que se buscam despertar os diferentes gêneros literários.&lt;/p&gt;

&lt;p&gt;**O autor adverte, qualquer semelhança com eventos reais, pessoas vivas ou mortas é mera coincidência 😁&lt;/p&gt;

&lt;p&gt;Feito o preâmbulo, você está ansioso para saber o que o seu código conta sobre você? E qual é o gênero literário que você seria encaixado se o seu código fosse um livro?&lt;/p&gt;

&lt;h2&gt;
  
  
  Os gêneros literários dos programadores
&lt;/h2&gt;

&lt;p&gt;Comecemos por definir alguns gêneros e algumas características nos códigos normalmente atribuíveis àqueles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terror
&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%2Fzjw2c2ncauv4ywwn3fj0.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%2Fzjw2c2ncauv4ywwn3fj0.png" alt="Freddy krueger com a mão em frente ao rosto levemente espantado" width="406" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Todos nós em algum momento da vida já tivemos que lidar com algum código que nos assustou quando estávamos lendo, e que nos rendeu alguns pesadelos a noite. De fato, existem algumas coisas que são o terror dos programadores, confere só essa pequena lista e me diga se isso não te dá um frio na espinha:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arquivos com o número de linhas intermináveis;&lt;/li&gt;
&lt;li&gt;Linhas de código que poderiam dar a volta no planeta Terra;&lt;/li&gt;
&lt;li&gt;O mesmo nome de variável sendo usada para várias coisas diferentes;&lt;/li&gt;
&lt;li&gt;Todos os arquivos do projeto na pasta raiz do repositório;&lt;/li&gt;
&lt;li&gt;Funções que passam como parâmetro a chamada de outras funções, que passam como parâmetros a chamada de outras funções, que passam como parâmetro a chamada de outras funções, que passam como parâmetro a chamada de outras funções.... Só para deixar claro, essa crítica não se aplica em linguagens funcionais 😁.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E por fim, e mais assustador, alguns programadores adoram esquartejar suas variáveis, muitas vezes, tudo que sobra para trás para contar história é um X marcando o local onde o ataque aconteceu.&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="nx"&gt;lst&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;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SOCORRO&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Suspense
&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%2Fi.gifer.com%2FMVV3.gif" 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%2Fi.gifer.com%2FMVV3.gif" width="500" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alguns códigos, quando precisamos debugá-los, nos dão a mesma experiência de ler um bom livro de suspense.&lt;/p&gt;

&lt;p&gt;Os códigos que estou classificando aqui como suspense são aqueles que todas as vezes que executamos, não sabemos o que esperar, às vezes funciona, às vezes gera um erro, às vezes retorna um resultado, às vezes outro.&lt;/p&gt;

&lt;p&gt;Isso costuma acontecer quando uma função faz várias coisas e possui vários efeitos colaterais, além de não deixar claro o que a mesma pretendia fazer.&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;function&lt;/span&gt; &lt;span class="nf"&gt;funcao1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objeto&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o dia está ensolarado&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bora curtir uma praia&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o vento está para o norte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;objeto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;propriedade&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;está chovendo&lt;/span&gt;&lt;span class="dl"&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="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;O Dev pira&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ficção
&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%2Fochihzto3v9pkisvwhm8.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%2Fochihzto3v9pkisvwhm8.png" alt="Astronauta voando solto no espaço sideral" width="800" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ficção definitivamente é um gênero muito popular, pelo menos quando se trata de livros, quem nunca viu uma obra de Isaac Asimov? Quando falamos de algoritmos de computadores, esse gênero não é tão popular assim, é raro, mas acontece com frequência 😁.&lt;/p&gt;

&lt;p&gt;Obras de ficção costumam brincar com a realidade, e desafiam o nosso conhecimento ou extrapolam teorias, nos algoritmos de computadores isso costuma ser visto quando o autor escreve uma função cujo objetivo do que se busca e do que se faz só pode ser ficcional.&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;function&lt;/span&gt; &lt;span class="nf"&gt;somarNumeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;right&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;left&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;right&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;
  
  
  Romance
&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%2Fi9hl9kcmfx0tif3xvyq3.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%2Fi9hl9kcmfx0tif3xvyq3.png" alt="Filme a dama e o vagabundo, com os cães comendo um mesmo pedaço de espaguete" width="728" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O amor é lindo, e mais lindo que o amor é um código escrito com paixão. Programadores experientes conseguem ver através do código e dizer com quanto carinho o código foi escrito pelo autor.&lt;/p&gt;

&lt;p&gt;Poucas coisas são tão satisfatórias quanto trabalhar com um código que foi escrito com esmero, é possível sentir quando o programador se esforçou em tornar o seu trabalho entendível e lapidado. Ainda que não seja o melhor código possível, e não se trata disso! Um programador que escreve romances toma o cuidado de deixar as coisas onde se espera que elas estejam, e conduzem o leitor de seus códigos em uma valsa de funções e variáveis imitando o mais belo dos sonetos.&lt;/p&gt;

&lt;p&gt;Escritores deste gênero tomam o cuidado de indentar seus códigos com um padrão bem estabelecido, ainda que o leitor prefira outras formatações, é notável que o autor se esforçou para manter tudo com a mesma estética, e não jogou simplesmente os elementos na tela como quem bate com a cabeça no teclado.&lt;/p&gt;

&lt;h2&gt;
  
  
  As revelações que os códigos fazem sobre seus autores
&lt;/h2&gt;

&lt;p&gt;Tendo visto alguns gêneros literários usados para falar de características gerais dos desenvolvedores, daremos sequência observando algumas características mais pontuais, itens que os códigos revelam sobre os autores.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programador Ultrawide Screen
&lt;/h3&gt;

&lt;p&gt;Alguns programadores usam todo o espaço disponível de seus monitores para escrever seus códigos, pode ser muito fácil descobrir o tamanho do monitor de alguns desenvolvedores, basta contar quantas vezes você precisa rolar o código horizontalmente para descobrir se o desenvolvedor que o fez possui um monitor Ultrawide Screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programador Shakespeariano
&lt;/h3&gt;

&lt;p&gt;Esses programadores normalmente escrevem códigos que se encaixam no gênero de romance, suas obras são em geral muito belas, o único problema é que poucas pessoas são capazes de entendê-las.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programadores que amam e odeiam espaço em branco
&lt;/h3&gt;

&lt;p&gt;Alguns programadores amam usar a tecla de espaço, adicionam vários espaços entre seus códigos, seja verticalmente deixando um vasto espaço vazio entre funções, ou horizontalmente iniciando uma linha na metade da tela.&lt;/p&gt;

&lt;p&gt;Por outro lado, há aqueles que a detestam, não incluem espaços entre elementos de uma linha, e muito menos entre blocos de funções, tudo se torna uma grande sequência de caracteres concatenados.&lt;/p&gt;

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

&lt;p&gt;Ler e interpretar códigos compõem a maior parte do trabalho de um desenvolvedor, seja para integrar uma nova feature à um código já existente, corrigir um bug, ou refatorar algum trecho de código. Estamos sempre lendo códigos e tentando entender o que raios ele está fazendo, seja esse escrito por alguém da nossa equipe ou por nós mesmos há alguns meses. Por esse motivo, escrever de forma consistente e aplicar corretamente os padrões de desenvolvimento são tão importantes, isso nos ajuda a comunicar a intenção do código para as outras pessoas, e para nós mesmos no futuro.&lt;/p&gt;

&lt;p&gt;O objetivo deste texto foi chamar a atenção de forma divertida para alguns anti-patterns e vícios negativos que temos no desenvolvimento de código, de forma que quando estejamos escrevendo algum código, nos perguntemos: que tipo de estória eu estou contando? Quem está lendo meu código se sentirá lendo um romance ou uma estória de terror?&lt;/p&gt;

&lt;p&gt;É sempre mais agradável lidar com código claros e bem escritos, ainda que o código não seja o melhor, é possível notar quando o desenvolvedor se importava com o que estava fazendo, e queria entregar o melhor que podia naquele momento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dicas do autor
&lt;/h2&gt;

&lt;p&gt;Quer deixar de escrever estórias de terror e começar a escrever verdadeiros romances? Que tal começar aplicando algumas estratégias de &lt;em&gt;clean code&lt;/em&gt; básicas?&lt;/p&gt;

&lt;p&gt;Preparei uma pequena lista de tópicos pensando no que vimos dentro dos gêneros literários deste artigo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nem todos os desenvolvedores possuem um super monitor, controle o comprimento das linhas do seu código, 80 caracteres é excelente, 120 é aceitável;&lt;/li&gt;
&lt;li&gt;Se o arquivo está muito grande, separe o código em arquivos menores de acordo com as responsabilidades do código;&lt;/li&gt;
&lt;li&gt;Separou o código em vários arquivos? Ótimo, agora os organize em pastas no seu projeto, não deixe tudo na pasta raiz;&lt;/li&gt;
&lt;li&gt;Use nomes reveladores nas variáveis e funções, abreviaturas e usar apenas uma letra como variável dificulta muito a manutenção do código;&lt;/li&gt;
&lt;li&gt;Certifique-se de que a função escrita faz o que o nome dela expressa;&lt;/li&gt;
&lt;li&gt;Use o espaço vertical e horizontal, mas também não exagere, os elementos não precisam estar unidos, mas também não precisam estar em quarentena um longe do outro;&lt;/li&gt;
&lt;li&gt;Siga apenas uma indentação, mesmo que não seja a melhor de todas ela demonstra consistência, poucas coisas mostram mais desleixo do que cada parte de um código escrito e indentado de formas completamente diferentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lembre-se: escritores de livros não publicam a primeira versão de seus manuscritos, eles leem e releem suas obras e as lapidam, do mesmo jeito, você não deveria publicar a primeira versão do seu código, uma revisão ainda que rápida não fará mal a ninguém.&lt;/p&gt;

&lt;p&gt;Agora, me conta: que tipo de gênero literário você tem escrito atualmente?&lt;/p&gt;

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

&lt;p&gt;React e ficção: &lt;a href="https://www.youtube.com/watch?v=kqh4lz2Lkzs" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=kqh4lz2Lkzs&lt;/a&gt;&lt;br&gt;
Livro: Código limpo: habilidades práticas do Agile software&lt;/p&gt;

</description>
    </item>
    <item>
      <title>CUIDADO: Seu Código Pode Estar Vulnerável. Descubra como Dependency Check + Azure DevOps + SonarQube = Segurança!</title>
      <dc:creator>Luiz Felipe Lago</dc:creator>
      <pubDate>Fri, 15 Dec 2023 18:59:31 +0000</pubDate>
      <link>https://dev.to/becomex/cuidado-seu-codigo-pode-estar-vulneravel-descubra-como-dependency-check-azure-devops-sonarqube-seguranca-4n8e</link>
      <guid>https://dev.to/becomex/cuidado-seu-codigo-pode-estar-vulneravel-descubra-como-dependency-check-azure-devops-sonarqube-seguranca-4n8e</guid>
      <description>&lt;p&gt;A segurança no desenvolvimento de software se torna cada vez mais crucial e a combinação de ferramentas eficientes é essencial para garantir a integridade e a proteção de aplicações. &lt;/p&gt;

&lt;p&gt;Este artigo explora a integração do Dependency Check com o Azure DevOps, destacando a capacidade de unificar relatórios de segurança com o SonarQube por meio de um plugin oficial.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  &lt;strong&gt;Dependency Check:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Visão Geral:&lt;/strong&gt;&lt;br&gt;
Desenvolvido e mantido pela OWASP (Open Web Application Security Project), o Dependency Check é uma ferramenta de código aberto que identifica e alerta sobre bibliotecas de terceiros com vulnerabilidades conhecidas. Suportando várias linguagens, o Dependency Check verifica dependências em busca de componentes suscetíveis a falhas de segurança, promovendo uma abordagem proativa à segurança. Documentação em &lt;a href="https://owasp.org/www-project-dependency-check"&gt;OWASP DEPENDENCY CHECK&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Integração com Azure DevOps:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A integração do Dependency Check com o Azure DevOps proporciona uma verificação contínua de vulnerabilides durante o ciclo de vida do desenvolvimento. Automatizando o processo de análise de segurança, essa integração garante a detecção e correção de vulnerabilidades antes que o código chegue à produção.&lt;br&gt;
A task do Dependency Check para o Azure DevOps pode ser encontrada no Marketplace do Azure DevOps, acessível no link &lt;a href="https://marketplace.visualstudio.com/items?itemName=dependency-check.dependencycheck."&gt;Azure DevOps Marketplace&lt;/a&gt; Essa tarefa permite a fácil incorporação do Dependency Check nos pipelines de build do Azure DevOps, simplificando a implementação da verificação de segurança.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Integração com SonarQube via Plugin:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Para centralizar os relatórios de segurança do Dependency Check no SonarQube, utiliza-se o plugin oficial disponível em &lt;a href="https://github.com/dependency-check/dependency-check-sonar-plugin"&gt;Plugin Oficial&lt;/a&gt;. Este plugin permite uma integração fácil e eficiente, proporcionando uma visão consolidada dos resultados de segurança diretamente no Sonar.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Verificação de Compatibilidade com o SonarQube:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;O plugin do Dependency Check para SonarQube é compatível com diversas versões do SonarQube. Antes de realizar a instalação, é recomendável verificar a documentação ou o repositório do plugin para garantir sua compatibilidade com a versão específica do SonarQube utilizada.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Benefícios da Integração:&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralização de Relatórios:&lt;/strong&gt; A integração com o SonarQube via plugin proporciona uma centralização eficiente de relatórios de segurança, simplificando a análise e o acompanhamento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Análise Estática de Código:&lt;/strong&gt; A combinação da verificação de dependências e vulnerabilidade do Dependency Check com a análise estática de código do SonarQube oferece uma visão holística da qualidade e segurança do código-fonte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detecção Antecipada de Problemas:&lt;/strong&gt; A detecção precoce de vulnerabilidades, juntamente com métricas fornecidas pelo SonarQube, possibilita os desenvolvedores corrigirem problemas antes que impactem a segurança e a qualidade do software.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A integração do Dependency Check com o Azure DevOps, combinada com a centralização de relatórios no SonarQube por meio do plugin, oferece uma abordagem robusta para fortalecer a segurança no ciclo de vida do desenvolvimento. A colaboração entre essas ferramentas, permite a detecção e correção eficaz de vulnerabilidades, garantindo que as organizações possam oferecer software seguro, resiliente e de alta qualidade.&lt;/p&gt;

&lt;p&gt;E vocês já conhecem o Fossology? Não? Essa assunto fica para o próximo capítulo dessas pílulas de segurança...&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>azure</category>
      <category>sonarqube</category>
      <category>dependencycheck</category>
    </item>
    <item>
      <title>Gerenciando Processos Concorrentes: Estratégias e Dicas</title>
      <dc:creator>Renan Osório</dc:creator>
      <pubDate>Fri, 24 Nov 2023 11:51:57 +0000</pubDate>
      <link>https://dev.to/becomex/gerenciando-processos-concorrentes-estrategias-e-dicas-3bdl</link>
      <guid>https://dev.to/becomex/gerenciando-processos-concorrentes-estrategias-e-dicas-3bdl</guid>
      <description>&lt;p&gt;A programação concorrente é uma parte fundamental da computação moderna. À medida que os processadores evoluem e as aplicações se tornam cada vez mais complexas, a capacidade de executar múltiplas threads ou processos simultaneamente se torna essencial para otimizar o desempenho e a responsividade dos sistemas. No entanto, essa abordagem traz consigo o desafio de lidar com a concorrência, na qual várias threads competem por recursos compartilhados. E é aí que entram os conceitos de Mutex e Lock, duas ferramentas cruciais para gerenciar essa concorrência de maneira eficaz. &lt;/p&gt;

&lt;p&gt;Esses recursos desempenham um papel fundamental em cenários nos quais é imperativo assegurar que apenas uma thread execute o recurso, prevenindo assim duplicação. Esse mecanismo de bloqueio é aplicado por um intervalo de tempo definido, o que significa que um método é temporariamente retido por uma thread durante um período determinado com o propósito de garantir que nenhuma outra thread execute o mesmo método simultaneamente. &lt;/p&gt;

&lt;p&gt;Esses conceitos fazem o bloqueio de threads concorrentes tanto em aplicações que possuem uma única instância, quanto em aplicações distribuídas em diversas instâncias como, por exemplo, o uso de clusters.  &lt;/p&gt;

&lt;p&gt;Neste artigo, pretendo elucidar alguns conceitos e oferecer orientações para a implementação de Mutex e Lock. &lt;/p&gt;

&lt;h2&gt;
  
  
  Tempo de Expiração e Base de dados
&lt;/h2&gt;

&lt;p&gt;A base de dados é responsável por guardar os dados dos processos que estão bloqueados. Por exemplo, quando for pagar um boleto, deve ser gravado no banco uma chave com os dados desse boleto para indicar que esse boleto está sendo processado. E, ao fazer isso, é preciso indicar por quanto tempo esse recurso será bloqueado. &lt;/p&gt;

&lt;p&gt;O recomendado é utilizar uma base de dados que já possua um recurso automático de expiração de dados, já que os dados nela são voláteis. Além disso, essa base de dados deve ser rápida para leitura e gravação. &lt;/p&gt;

&lt;p&gt;Recomendo a utilização do Redis, e, nele, gravar um json com os seguintes dados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"registro": {
        "key": "lib_lock:appName:Environment:IdBoleto",
        "threadId": 0,
        "hostName": "",
        "processName": "",
        "processId": 0,
        "nameOf": "",
        "dataCriacao": "",
        "tempoExpiracao": "",
        "tempoRestanteExpiracao": ""
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O redis é um banco de &lt;strong&gt;chave&lt;/strong&gt; e &lt;strong&gt;valor&lt;/strong&gt;. A &lt;strong&gt;chave&lt;/strong&gt; será a mesma que está no json citado anteriormente, e o &lt;strong&gt;valor&lt;/strong&gt; será todo o json citado.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chave
&lt;/h3&gt;

&lt;p&gt;O controle de bloqueio é feito através de uma chave, que contém dados necessários para distinguir processos, ambientes e o registro que está sendo bloqueado. &lt;/p&gt;

&lt;p&gt;Assim, garantimos que, quando gravarmos uma chave na base de dados, esse registro não será processado novamente sem que a chave expire ou seja deletada da base de dados. &lt;/p&gt;

&lt;p&gt;O ideal é uma padronização de uma chave, podemos fazer da seguinte maneira:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chave Lock&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;lib_lock:NomeAplicacao:Environment:Boleto-11111&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Chave Mutex&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;lib_mutex_queue:NomeAplicacao:Environment:Boleto-11111:HostaName:ThreadId:ProcessId&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como o Mutex faz controle de fila das threads, é necessário ter mais dados na chave para facilitar o trabalho de distinguir os itens na fila. &lt;/p&gt;

&lt;p&gt;O atributo Boleto-1111 que está na chave informa o tipo do dado, que nesse caso é um boleto, e mostra o identificador único do registro, que nesse caso é 1111. Já os demais dados podem ser preenchidos da forma que achar mais adequada para o seu projeto. &lt;/p&gt;

&lt;h2&gt;
  
  
  Mutex
&lt;/h2&gt;

&lt;p&gt;O termo "Mutex" é a abreviação de "Mutual Exclusion", o que significa exclusão mútua. Essencialmente, um Mutex é um mecanismo de sincronização usado para garantir que apenas uma thread por vez tenha acesso a um recurso compartilhado. Uma das funcionalidades mais valiosas do Mutex é a sua capacidade de enfileirar threads concorrentes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluxo
&lt;/h3&gt;

&lt;p&gt;O funcionamento geral do Mutex é ilustrado na imagem abaixo.&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%2Fz511wl4gqz3shbi8iv2j.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%2Fz511wl4gqz3shbi8iv2j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  WaitOne
&lt;/h3&gt;

&lt;p&gt;É necessário que o Mutex tenha o recurso de WaitOne, que é responsável por gravar na base de dados que um determinado recurso está bloqueado e ficar travado até que chegue a sua vez de processar o recurso. &lt;/p&gt;

&lt;p&gt;O WaitOne é responsável também por realizar a sincronia da fila no redis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Processo Lógico de Mutex
&lt;/h3&gt;

&lt;p&gt;Na imagem abaixo, temos o processo sugerido para fazer um controle de Mutex por meio do WaitOne e garantir que tenha um enfileiramento de threads:&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%2Fc5avpr2m78cvvjjn1y86.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%2Fc5avpr2m78cvvjjn1y86.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lock
&lt;/h2&gt;

&lt;p&gt;O "Lock" representa outra abordagem para controlar threads concorrentes. Nesse cenário, o "Lock" bloqueia um processo por um período definido, e todas as futuras threads que tentarem acessar o mesmo recurso já bloqueado serão encerradas. &lt;/p&gt;

&lt;p&gt;A principal diferença entre o "Mutex" e o "Lock" reside no fato de que o "Mutex" enfileira todas as threads que tentam acessar um recurso já bloqueado e, à medida que essas threads são processadas, permite que a próxima thread seja executada. Por outro lado, o "Lock" encerra todas as threads concorrentes, permitindo que apenas uma única thread seja executada. &lt;/p&gt;

&lt;h3&gt;
  
  
  Fluxo
&lt;/h3&gt;

&lt;p&gt;O funcionamento geral do Lock é ilustrado na imagem abaixo.&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%2Fgmvvb6q4rsrrg7w30mzf.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%2Fgmvvb6q4rsrrg7w30mzf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AcquireLock
&lt;/h3&gt;

&lt;p&gt;Essa funcionalidade tem a responsabilidade de registrar o processo que está sendo bloqueado na base de dados. Caso o processo já esteja bloqueado, deve gerar uma exceção. &lt;/p&gt;

&lt;p&gt;Ao contrário do "WaitOne", essa funcionalidade não cria nem gerencia filas, ela apenas encerra a requisição. &lt;/p&gt;

&lt;h2&gt;
  
  
  ReleaseLock
&lt;/h2&gt;

&lt;p&gt;O Mutex e o Lock devem ambos possuir a funcionalidade de "ReleaseLock", que tem a responsabilidade de desbloquear o processo na base de dados. &lt;/p&gt;

&lt;p&gt;O desbloqueio do processo na base de dados pode ser alcançado de duas maneiras: por meio da expiração do dado na base de dados (caso esteja sendo utilizado o Redis) ou simplesmente removendo-o da base de dados usando a função "ReleaseLock". &lt;/p&gt;

&lt;p&gt;Por exemplo, ao concluir o processamento de um boleto, o "ReleaseLock" será invocado, resultando na remoção da chave correspondente a esse boleto na base de dados. &lt;/p&gt;

&lt;h2&gt;
  
  
  KeepLock e/ou DelayMutex
&lt;/h2&gt;

&lt;p&gt;Este recurso pode ser bastante útil, pois permitirá estender o período de bloqueio, caso seja necessário. Por exemplo, se houver algum trecho de código que, no pior cenário, possa resultar em longos atrasos, pode ser necessário ajustar a duração do bloqueio do registro no banco de dados. Esse recurso pode ser denominado como "KeepLock" quando se refere ao bloqueio de Lock, e "DelayMutex" quando se relaciona ao Mutex. &lt;/p&gt;

&lt;h1&gt;
  
  
  Monitoramento
&lt;/h1&gt;

&lt;p&gt;É fundamental contar com um sistema de monitoramento para os logs gerados por todos os recursos de Mutex e lock, bem como monitorar a base de dados onde os dados de bloqueio são registrados. Isso permite garantir a estabilidade da base de dados, identificar possíveis quedas e evitar bloqueios prolongados de dados. &lt;/p&gt;

&lt;p&gt;Recomendamos que você e sua equipe de arquitetos avaliem qual é a ferramenta de monitoramento mais adequada para o seu cenário. &lt;/p&gt;

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

&lt;p&gt;Os recursos mencionados são de suma importância para sistemas que necessitam assegurar que determinados recursos não sejam processados múltiplas vezes ou simultaneamente. &lt;/p&gt;

&lt;p&gt;Vale ressaltar que há diversas maneiras de implementar um Mutex ou Lock em seu projeto. Contudo, desde que sigam padrões estabelecidos e garantam a confiabilidade das execuções concorrentes de threads, evitando a duplicação de processamento de recursos, sua aplicação se tornará mais confiável, reduzindo custos desnecessários. &lt;/p&gt;

</description>
      <category>mutex</category>
      <category>lock</category>
    </item>
    <item>
      <title>Angular v10 vs v15: Principais mudanças e melhorias</title>
      <dc:creator>vandrei de lima</dc:creator>
      <pubDate>Mon, 23 Oct 2023 16:38:05 +0000</pubDate>
      <link>https://dev.to/becomex/angular-v10-vs-v15-principais-mudancas-e-melhorias-f72</link>
      <guid>https://dev.to/becomex/angular-v10-vs-v15-principais-mudancas-e-melhorias-f72</guid>
      <description>&lt;p&gt;Olá! &lt;/p&gt;

&lt;p&gt;Neste artigo, vou apresentar as principais melhorias e atualizações que ocorreram entre o Angular 10 e a versão 15 do framework. A migração de projetos Angular é crucial para aprimorar o desenvolvimento e a experiência final dos usuários. Para aqueles que atualmente utilizam em seus projetos o Angular 10, especialmente em conjunto com o Angular Material, é fundamental planejar a migração a fim de aproveitar ao máximo os recursos aprimorados disponíveis no Angular 15. O propósito deste artigo é fornecer uma lista das atualizações mais significativas e orientações sobre as migrações. &lt;/p&gt;

&lt;p&gt;Dentro das atualizações, tivemos melhorias significativas no core e no processamento do build e melhorias e avanços no NGCC (Angular compatibility compiler) que podem trazer uma velocidade de compilação de até 4x mais rápido, trazendo mais velocidade para o desenvolvimento. &lt;/p&gt;

&lt;p&gt;A versão 10 do angular consegue utilizar até a versão 3.9 do typescript e na 15 temos um grande avanço, podendo utilizar até a versão 5.0, trazendo benefícios e novas ferramentas para o desenvolvimento. Além disso, tivemos melhorias visuais na estrutura de log, facilitando a busca de problemas que podem ocorrer no desenvolvimento. Nas versões mais recentes, tivemos a depreciação do TSLint, de forma que agora é necessário migrar para o ESlint. &lt;/p&gt;

&lt;p&gt;Foi adicionado também o “Hot Module Reloading”, que uma vez ativado não requer a atualização de toda a tela quando é feita uma mudança em algum módulo ou componente. Isso também traz velocidade para quando estivermos fazendo alterações em alguma tela na qual o tempo de carregamento é alto. &lt;/p&gt;

&lt;p&gt;Para ativar o HMR, basta iniciar o server utilizando o parâmetro --hmr:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve &lt;span class="nt"&gt;--hmr&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, também podemos utilizar a coalescência nula no template e, com isso, além de poder utilizar a condição ternária, também podemos criar condições de forma mais simples. Confira o exemplo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;Ternario&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;age&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;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="nx"&gt;Coalescência&lt;/span&gt; &lt;span class="nx"&gt;nula&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A estrutura de um projeto angular é separada por módulos. E isso para quem está iniciando pode gerar um pouco de confusão. Mas não se preocupe, não é nada complexo: o lado positivo dos módulos é conseguir gerar um carregamento por demanda e com isso só será executado o código que for necessário. Isso ajuda a evitar carregamento desnecessário de script.  &lt;/p&gt;

&lt;p&gt;O problema atual é o seguinte: ao criar um dumb component (componente genérico sem regra de negócio) que seria compartilhado com outros módulos, você precisa criar um módulo apenas para ele e com isso importar nos módulos os locais nos quais gostaria de utilizar. Porém, na versão 14 do angular, foi estabilizado os “standalones” componentes, no qual um componente pode importar outros módulos para utilizar e pode ser importado por qualquer outro módulo, sendo independente de um módulo pai.  &lt;/p&gt;

&lt;p&gt;Isso ajuda e facilita bastante, sem essa ferramenta alguns projetos criam os “sharedModule” nos quais eles importam e declaram vários componentes. E o problema é que às vezes queremos utilizar apenas um ou dois componentes e precisamos importar o módulo inteiro. Com os “standalones” componentes, isso será resolvido: você apenas importará os componentes necessários, diminuindo a quantidade de código carregado pelo navegador. &lt;/p&gt;

&lt;p&gt;Aqui está um exemplo de como seria um "standalone component":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="c1"&gt;// declara um standalone component&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;photo-gallery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ImageGridComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// importa os modulos utilizados por ele&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    ... &amp;lt;image-grid [images]="imageList"&amp;gt;&amp;lt;/image-grid&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PhotoGalleryComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// component logic&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, basta importar esse componente no módulo que deseja utilizar e pronto: estará pronto para o uso. &lt;/p&gt;

&lt;p&gt;Para a injeção de dependência, tivemos algumas melhorias e a maneira de declarar ficou facilitada. A partir de agora, temos o método &lt;strong&gt;inject()&lt;/strong&gt; e a sua principal vantagem é poder realizar a injeção de dependência sem precisar declarar explicitamente o tipo do parâmetro, de forma a tornar o código mais limpo e legível.&lt;/p&gt;

&lt;p&gt;Veja o exemplo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ActivatedRoute&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getRouteParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ActivatedRoute&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-todo-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./todo-page.component.html&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoPageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRouteParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&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="k"&gt;this&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="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;Tivemos melhorias gerais de acessibilidade, tanto para os componentes como para as rotas, que deixaram os componentes mais estáveis. Além disso, tivemos melhorias nas diretivas, de forma a permitir a inclusão nos elementos host e a estabilizar as diretivas para imagens.  &lt;/p&gt;

&lt;p&gt;Agora, se você for realizar uma migração extensa como essa partindo do angular 10 para o 15, eu tenho aqui algumas recomendações: &lt;/p&gt;

&lt;p&gt;Comece a migração como uma escada, não parta do 10 direto para o 15, vá subindo gradualmente as versões do angular. Isso evita dores de cabeça e facilita identificar caso alguma biblioteca fique estagnada e não possa mais ser utilizada. Verifique a lib dos componentes e, caso esteja utilizando o angular material, fique atento às alterações de certos componentes (alguns mudaram até os seletores).   &lt;/p&gt;

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

&lt;p&gt;Neste artigo, exploramos as principais mudanças que ocorreram no Angular, desde a versão 10 até a versão 15. Ao destacar essas transformações, meu objetivo foi proporcionar a você uma compreensão mais clara das novas ferramentas e recursos disponíveis, e mostrar como você pode aproveitá-los para melhorar o desenvolvimento de seus aplicativos Angular. &lt;/p&gt;

&lt;p&gt;No entanto, é fundamental notar que o Angular é uma plataforma em constante evolução. A partir da versão 16, testemunhamos mudanças significativas, inclusive na abordagem para o gerenciamento de estado e em muitos outros aspectos.  &lt;/p&gt;

&lt;p&gt;Portanto, se você estiver considerando a migração para as versões mais recentes do Angular, este artigo serviu como um ponto de partida, mas é altamente recomendável manter-se atualizado com a documentação oficial e as comunidades do Angular para aproveitar ao máximo essas novas oportunidades. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Executando funções personalizadas no banco de dados usando SqlExpression no .Net</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Sat, 06 May 2023 20:26:24 +0000</pubDate>
      <link>https://dev.to/becomex/executando-funcoes-personalizadas-no-banco-de-dados-usando-sqlexpression-no-net-28i</link>
      <guid>https://dev.to/becomex/executando-funcoes-personalizadas-no-banco-de-dados-usando-sqlexpression-no-net-28i</guid>
      <description>&lt;p&gt;Olá, pessoal! Espero encontrar todos bem. Hoje teremos um material "mão na massa", demonstrando como fazer o EF Core (Entity Framework Core) ser capaz de traduzir funções personalizadas no banco de dados em expressões construídas com Linq (Consulta Integrada à Linguagem), que normalmente, não seria possível traduzi-las.&lt;/p&gt;

&lt;p&gt;Se você trabalha com a linguagem de programação C#, certamente já escreveu alguma &lt;em&gt;query&lt;/em&gt; com Linq que executa perfeitamente quando a lista de dados da operação envolvida já está carregada em memória, mas teve uma triste surpresa ao tentar aplicar o mesmo código acessando dados que estavam no banco, recebendo algum erro similar a este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; The LINQ expression could not be translated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso ocorre porque há um limite acerca do que o EF Core é capaz de traduzir para linguagem nativa do banco de dados configurado em seu projeto, restringindo assim as possibilidades de uso do que pode ser feito diretamente no banco, em ralação ao que pode ser feito quando os dados já estão em memória. Mas há uma luz no fim do túnel, e não se preocupe, não é um trem vindo em sua direção... Podemos usar o recurso &lt;em&gt;SqlExpression&lt;/em&gt; para ensinar o EF Core a traduzir comandos que ele nativamente não consegue, sendo essas operações nativas do seu banco de dados, ou funções criadas por você dentro do banco de dados.&lt;/p&gt;

&lt;p&gt;Antes de começarmos efetivamente, vamos dar uma olhada nas versões de pacotes e programas que estou usando, sabemos que o modo como os recursos são implementados podem variar de acordo com suas versões, então para não haver mal-entendidos, estou usando o .Net 5 e o banco de dados SQL Server 2016, um pouco datado, eu sei.&lt;/p&gt;

&lt;p&gt;Vamos começar com um problema simples. Imagine que você precise realizar uma consulta em uma massa de dados de &lt;em&gt;Players&lt;/em&gt;, e retornar às seguintes propriedades: &lt;em&gt;Name&lt;/em&gt;, &lt;em&gt;Score&lt;/em&gt;, e a posição do player no ranking, que claro, é calculado a partir do Score. Para atender a essa demanda, um simples código como o seguinte pode ser usado&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;playerList&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;Player&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;Player&lt;/span&gt;&lt;span class="p"&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="s"&gt;"Mauricio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&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;Player&lt;/span&gt;&lt;span class="p"&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="s"&gt;"André"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Score&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Player&lt;/span&gt;&lt;span class="p"&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="s"&gt;"Redmerski"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Score&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="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;playerDtoList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;playerList&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&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;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PlayerDto&lt;/span&gt;&lt;span class="p"&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;player&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;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Position&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&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;})&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse código funciona perfeitamente porque os dados que esse algoritmo manipula estão carregados em memória, se você trocar a variável playerList de modo a apontar para uma base de dados, usando &lt;code&gt;dbContext.PlayersDbSet&lt;/code&gt; por exemplo, descobrirá que isso não pode ser traduzido para um comando SQL. O parâmetro &lt;em&gt;index&lt;/em&gt; contido no &lt;em&gt;Select&lt;/em&gt; representa a posição do item percorrido dentro da lista carregada em memória, logo se os dados não estão em memória, essa informação não existe. Poderíamos esperar que essa posição fosse substituída pela função do banco de dados que determina a linha da consulta, chamado de &lt;em&gt;ROW_NUMBE&lt;/em&gt; no SQL Server, mas o EF Core não tem uma forma simples de executar essa operação para retornar o número da linha do registro em uma consulta ao banco de dados.&lt;/p&gt;

&lt;p&gt;PS: Eu sei que você está com vontade de comentar que esse código não prevê a possibilidade de dois ou mais jogadores estarem empatados, mas quero manter as coisas simples, então segura essa vontade 😁.&lt;/p&gt;

&lt;p&gt;Certo, então como podemos tornar essa operação traduzível ao banco de dados? Muito simples meu caro leitor, basta seguirmos os passos abaixo. Ah, os nomes e estruturas que mostro abaixo são uma representação de como eu acredito que essas funções devem ser organizadas, fique à vontade para alterá-las.&lt;/p&gt;

&lt;p&gt;Começamos criando um diretório dentro do seu projeto responsável por lidar com a infraestrutura, especificamente o banco de dados, chamo essa pasta de &lt;em&gt;Functions&lt;/em&gt;, dentro dessa pasta crio um arquivo chamado &lt;em&gt;EfCoreCustomFunctions&lt;/em&gt;, dentro desse crio uma função chamada &lt;em&gt;RowNumber&lt;/em&gt; que recebe três parâmetros, um parâmetro do tipo &lt;em&gt;long&lt;/em&gt; que representará a coluna do banco de dados também do mesmo tipo que será usada para particionar a enumeração, um segundo parâmetro do tipo &lt;em&gt;long&lt;/em&gt; que representará a coluna pela qual a ordenação deve ser aplicada para a enumeração, e um parâmetro &lt;em&gt;booleano&lt;/em&gt; que indica a direção de ordenação, quando verdadeiro a ordem é ascendente. Observe que o conteúdo dessa função não é importante, então podemos simplesmente lançar uma exceçã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;using&lt;/span&gt; &lt;span class="nn"&gt;System&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;MyProject.EntityFrameworkCore&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EfCoreCustomFunctions&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;static&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;RowNumber&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;partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;ordering&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="k"&gt;ascending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&amp;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;NotSupportedException&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;Em seguida crio um arquivo na mesma pasta chamado &lt;em&gt;RowNumberFunction&lt;/em&gt;, é dentro desse arquivo que a função realmente será criada. Nesse arquivo crio uma função de extensão para a classe &lt;em&gt;ModelBuilder&lt;/em&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;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.EntityFrameworkCore&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RowNumberFunction&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;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddRowNumberFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&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;modelBuilder&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;A primeira coisa a ser feita é recuperar o tipo da classe que criamos para manter as assinaturas dos nossos métodos, e usar a função &lt;em&gt;GetMethod&lt;/em&gt; para capturar a assinatura do método específico desejado. Eu gosto de especificar explicitamente os tipos dos parâmetros da função em questão, passando-os como segundo parâmetro da função &lt;em&gt;GetMethod&lt;/em&gt;, mas se houver apenas uma função com o nome especificado, essa etapa é opcional.&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;method&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;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowNumber&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&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="kt"&gt;long&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="kt"&gt;long&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="kt"&gt;bool&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 seguida vem o passo mais importante: instruir o EF Core de fato a como traduzir esse comando, e podemos fazer isso de algumas formas&lt;/p&gt;

&lt;p&gt;Depois de usar o &lt;em&gt;modelMuilder&lt;/em&gt; para chamar a função &lt;em&gt;HasDbFunction&lt;/em&gt; passando como parâmetro a variável &lt;em&gt;method&lt;/em&gt; criada na etapa anterior, podemos usar a função &lt;em&gt;HasName&lt;/em&gt; e passar o nome de uma função personalizada que nós criamos diretamente no banco.&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="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;HasName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MinhaFuncaoJaCriadaNaBase"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eu particularmente não gosto de criar funções diretamente no banco de dados, entendo como a melhor opção usarmos o método &lt;em&gt;HasTranslation&lt;/em&gt; após a função &lt;em&gt;HasDbFunction&lt;/em&gt;, esse método nos permite instruir o EF Core a como a operação precisa ser criada, sem que a função exista previamente na base, assim mantemos todas as regras de operação dentro do nosso programa. É claro que esse é um posicionamento particular, a função &lt;em&gt;HasName&lt;/em&gt; existe para ser usada, então fique à vontade para fazer uso da mesma caso ela atenda ao seu cenário.&lt;/p&gt;

&lt;p&gt;A função &lt;em&gt;HasTranslation&lt;/em&gt; recebe uma &lt;em&gt;function&lt;/em&gt; que contém uma lista de &lt;em&gt;SqlExpression&lt;/em&gt;, essa lista é uma representação dos parâmetros que foram enviados para a função, e retorna um &lt;em&gt;SqlExpression&lt;/em&gt; que será a função a ser executada. Sim, os tipos de entrada e saídas são iguais, isso porque o parâmetro da sua função pode ser o resultado de uma outra função traduzida para o banco.&lt;/p&gt;

&lt;p&gt;A operação &lt;em&gt;RowNumber&lt;/em&gt; em que estamos trabalhando possui a classe &lt;em&gt;RowNumberExpression&lt;/em&gt; que facilita sua implementação e é herdeira de &lt;em&gt;SqlExpression&lt;/em&gt;. Essa classe recebe como parâmetro uma lista opcional com os campos da base a serem usados como partição de agrupamento para a enumeração das linhas, uma lista obrigatória da classe &lt;em&gt;OrderingExpression&lt;/em&gt; que contém o nome da coluna a ser usada na ordenação e a direção de ordenação, e o tipo de retorno esperado.&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="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&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;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&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="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;OrderingExpression&lt;/span&gt;&lt;span class="p"&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os parâmetros da função &lt;em&gt;RowNumber&lt;/em&gt; que criamos em nossa classe &lt;em&gt;EfCoreCustomFunctions&lt;/em&gt; são um pouco diferentes do que é esperado, então vamos manipulá-los um pouco. Primeiro vamos verificar se o primeiro parâmetro que enviamos é do tipo &lt;em&gt;SqlConstantExpression&lt;/em&gt;, qualquer constante enviada geraria o mesmo resultado, então eu prefiro testar essa condição, e caso ela seja verdadeira, passar o valor &lt;em&gt;null&lt;/em&gt; como parâmetro.&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="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&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;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&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="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;SqlConstantExpression&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="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&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="nf"&gt;ToList&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;OrderingExpression&lt;/span&gt;&lt;span class="p"&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida vamos criar um item na lista passada como segundo parâmetro, esse item vai ter os outros dois campos que recebemos em nossa função de ordenação personalizada. Observe que dada a natureza do tipo do objeto &lt;em&gt;args&lt;/em&gt;, precisamos primeiro converter o terceiro parâmetro recebido para &lt;em&gt;SqlConstantExpression&lt;/em&gt; para só então conseguir convertê-lo para &lt;em&gt;booleano&lt;/em&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="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&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;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&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="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;SqlConstantExpression&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="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&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="nf"&gt;ToList&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;OrderingExpression&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;OrderingExpression&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="nf"&gt;Skip&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="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="n"&gt;SqlConstantExpression&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="nf"&gt;Skip&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="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="n"&gt;Value&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="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código final dessa classe deve se parecer com o seguinte:&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;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&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;System.Data&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;System.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;Microsoft.EntityFrameworkCore&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;Microsoft.EntityFrameworkCore.Query.SqlExpressions&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;Microsoft.EntityFrameworkCore.Storage&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;MyProject.EntityFrameworkCore&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RowNumberFunction&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;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddRowNumberFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&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;method&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;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowNumber&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&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="kt"&gt;long&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="kt"&gt;long&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="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&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;=&amp;gt;&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&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="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;SqlConstantExpression&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="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&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="nf"&gt;ToList&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;OrderingExpression&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;OrderingExpression&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="nf"&gt;Skip&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="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                                &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="n"&gt;SqlConstantExpression&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="nf"&gt;Skip&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="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="n"&gt;Value&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="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&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;modelBuilder&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;Agora tudo que temos que fazer é chamar a construção desse método dentro do &lt;em&gt;ModelBuilder&lt;/em&gt;, para que quando tentarmos usá-lo, ele saiba exatamente o que fazer. Para isso, vamos criar uma classe chamada &lt;em&gt;ModelFunctionsExtensions&lt;/em&gt; dentro da pasta &lt;em&gt;Functions&lt;/em&gt;, vamos usar esse arquivo para chamar todas as funções customizadas que criaremos no futuro.&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;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&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;MyProject.EntityFrameworkCore&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelFunctionsExtensions&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;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRowNumberFunction&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;modelBuilder&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;Agora no local onde você cria o seu contexto, tudo que você tem a fazer é incluir a seguinte linha &lt;code&gt;builder.AddCustomFunctions();&lt;/code&gt; e todas as configurações estarão prontas. É claro que a variável &lt;em&gt;builder&lt;/em&gt; é uma instância de &lt;em&gt;ModelBuilder&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Agora vamos ver como podemos alterar o nosso código de exemplo para usar a função que acabamos de criar. Primeiro vamos acessar os dados diretamente do contexto, e na atribuição da propriedade &lt;em&gt;Position&lt;/em&gt;, vamos chamar nossa função &lt;em&gt;RowNumber&lt;/em&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;playerDtoList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;playerList&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&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;player&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PlayerDto&lt;/span&gt;&lt;span class="p"&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;player&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;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Position&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RowNumber&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="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto! Esse código será capaz de ser traduzido pelo EF Core, e a posição do player será calculada diretamente no banco de dados. Veja um exemplo de como essa &lt;em&gt;query&lt;/em&gt; se parecerá quando for executada no banco de dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&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;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;Position&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Playes&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Que tal olharmos rapidamente mais um exemplo de função, mas dessa vez um exemplo que use a classe &lt;em&gt;SqlFunctionExpression&lt;/em&gt;? Essa classe recebe como primeiro parâmetro o nome da função a ser executado, os argumentos a serem transmitidos, um indicador se o retorno pode ser nulo, e uma lista com o mesmo número de argumentos passados que representa a possibilidade de os parâmetros enviados serem nulos, um parâmetro do tipo &lt;em&gt;System.Type&lt;/em&gt; e outro &lt;em&gt;RelationalTypeMapping&lt;/em&gt; respectivamente, ambos indicando o tipo de retorno da função.&lt;/p&gt;

&lt;p&gt;Vamos criar um método que chama a função &lt;em&gt;Replicate&lt;/em&gt; do banco de dados, começamos incluindo a função &lt;em&gt;Replicate&lt;/em&gt; à nossa classe &lt;em&gt;EfCoreCustomFunctions&lt;/em&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;using&lt;/span&gt; &lt;span class="nn"&gt;System&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;MyProject.EntityFrameworkCore&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EfCoreCustomFunctions&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;static&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;RowNumber&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;partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;ordering&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="k"&gt;ascending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&amp;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;NotSupportedException&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;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Replicate&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;replicate&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;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&amp;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;NotSupportedException&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;Agora criamos o nosso arquivo &lt;em&gt;ReplicateFunction&lt;/em&gt; e criamos um conteúdo muito semelhante ao exemplo anterior, mas agora usando &lt;em&gt;SqlFunctionExpression&lt;/em&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;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&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;System.Data&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;System.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;Microsoft.EntityFrameworkCore&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;Microsoft.EntityFrameworkCore.Query.SqlExpressions&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;Microsoft.EntityFrameworkCore.Storage&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;MyProject.EntityFrameworkCore&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReplicateFunction&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;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddReplicateFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&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;method&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;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Replicate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&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="kt"&gt;string&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="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="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&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;=&amp;gt;&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlFunctionExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;"REPLICATE"&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="k"&gt;false&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="nf"&gt;Select&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="k"&gt;false&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="kt"&gt;string&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;StringTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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;modelBuilder&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;Agora basta incluir a linha &lt;code&gt;modelBuilder.AddReplicateFunction();&lt;/code&gt; na função &lt;em&gt;AddCustomFunctions&lt;/em&gt; do arquivo &lt;em&gt;ModelFunctionsExtensions&lt;/em&gt; e nossa função já está pronta para ser usada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nota do autor
&lt;/h2&gt;

&lt;p&gt;Conhecer recursos como esses a respeito da ferramenta com a qual trabalhamos é muito importante, e nos permite fazer coisas incríveis em nossas aplicações. Espero que esse artigo o tenha ajudado a resolver o que você precisava, ou ao menos incluído mais uma ferramenta em sua caixa de ferramentas para lidar com o complexo e maravilhoso mundo da programação.&lt;/p&gt;

&lt;p&gt;Abraço!&lt;/p&gt;

&lt;h2&gt;
  
  
  Fontes e leituras complementares
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.allhandsontech.com/data-professional/entityframework/entity-framework-core-advanced-mapping/" rel="noopener noreferrer"&gt;https://www.allhandsontech.com/data-professional/entityframework/entity-framework-core-advanced-mapping/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://khalidabuhakmeh.com/add-custom-database-functions-for-entity-framework-core" rel="noopener noreferrer"&gt;https://khalidabuhakmeh.com/add-custom-database-functions-for-entity-framework-core&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/56261258/mixing-ef-core-convensions-and-dbfunction-for-a-jobject-property" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/56261258/mixing-ef-core-convensions-and-dbfunction-for-a-jobject-property&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-hasdbfunction-191dd57e4967" rel="noopener noreferrer"&gt;https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-hasdbfunction-191dd57e4967&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-imethodcalltranslator-f8209ae6f95b" rel="noopener noreferrer"&gt;https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-imethodcalltranslator-f8209ae6f95b&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Uso do Codeball em projetos C#</title>
      <dc:creator>Ricardo Fontana</dc:creator>
      <pubDate>Wed, 19 Apr 2023 14:44:24 +0000</pubDate>
      <link>https://dev.to/becomex/uso-do-codeball-em-projetos-c-58o5</link>
      <guid>https://dev.to/becomex/uso-do-codeball-em-projetos-c-58o5</guid>
      <description>&lt;p&gt;São inegáveis os benefícios da revisão de código, como a redução do número de bugs, melhora da legibilidade do código, fortalecimento da cultura de feedback, entre outros. Porém, seguindo o velho princípio da física onde toda ação promove uma reação inversa e diretamente proporcional, a revisão de código pode gerar alguns "desconfortos" como a falta de clareza tanto por parte do autor quanto do revisor, falta de padronização e demora na revisão. A ferramenta &lt;a href="https://codeball.ai/" rel="noopener noreferrer"&gt;codeball.ia&lt;/a&gt; promete atuar neste último cenário, fazendo a revisão e aprovação automática dos pull requests. Para isso, a ferramenta utiliza algoritmos de inteligência artificial com percepção multinível e, segundo o site da ferramenta, são considerados critérios que vão desde o número de linhas alteradas até a classificação do tipo de arquivo. Baseando-se nestes critérios, a ferramenta gera um indicador do "percentual de confiança na alteração" e pode-se então definir algumas ações para este percentual como: aprovação automática ou adicionar uma marcação com o resultado.&lt;/p&gt;

&lt;p&gt;O blog da ferramenta ainda lista um caso de testes onde o codeball é comparado com PR previamente revisados. Este exemplo enfatiza que não houve falsos positivos durante o teste, sendo que este realmente parece ser o cenário mais catastrófico na utilização da ferramenta.&lt;/p&gt;

&lt;p&gt;Caso seu código esteja disponível no github, a instalação é extremamente simples: basta adicionar a action do codeball no workflow (no momento está sendo disponibilizada apenas a integração com o Github). A ferramenta é gratuita para projetos open source, para os demais há o custo de US$ 10,00 por usuário/mês, conforme o próprio site, entende-se por usuário o autor do pull request. No site existe ainda uma frase que chama muito a atenção "Pay only if Codeball saves you money" sem dar maiores detalhes sobre como obter este tipo de isenção.&lt;/p&gt;

&lt;p&gt;Para avaliar a eficiência do Codeball em projetos que utilizam dotnet e c#, selecionamos projetos que foram tendência no github em fevereiro de 2023, os procedimentos de pull request foram reproduzidos novamente a fim de se verificar se a ferramenta terá o mesmo resultado.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PR&lt;/th&gt;
&lt;th&gt;Confidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/PowerShell/PowerShell/pull/19119" rel="noopener noreferrer"&gt;https://github.com/PowerShell/PowerShell/pull/19119&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0.284&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/PowerShell/PowerShell/pull/19092" rel="noopener noreferrer"&gt;https://github.com/PowerShell/PowerShell/pull/19092&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0.372&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/PowerShell/PowerShell/pull/19111" rel="noopener noreferrer"&gt;https://github.com/PowerShell/PowerShell/pull/19111&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0.360&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/actions/runner/pull/2423" rel="noopener noreferrer"&gt;https://github.com/actions/runner/pull/2423&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0.376&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/actions/runner/pull/2396" rel="noopener noreferrer"&gt;https://github.com/actions/runner/pull/2396&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0.136&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Posteriormente, foi feito o mesmo procedimento de avaliar a eficiência dos projetos, porém utilizando repositórios internos da Becomex. O objetivo desta segunda bateria é verificar como a ferramenta se comporta com diferentes perfis de desenvolvedores ou mesmo se ela considera detalhes da localização do software na sua execução.&lt;/p&gt;

&lt;p&gt;Apesar do indicador de confiança apresentar melhora significativa, passando para aproximadamente 0.5, não foi o suficiente para a aprovação do PR. Não foi possível alcançar o&lt;/p&gt;

&lt;p&gt;percentual mínimo para aprovação mesmo em pequenas alterações que não comprometem o funcionamento da aplicação. Um exemplo deste tipo de alteração é a utilização dos recursos mais recentes da linguagem para a mesma funcionalidade.&lt;/p&gt;

&lt;p&gt;Dados os resultados alcançados, acredito que este é o momento ideal para nos fazermos uma indagação:&lt;/p&gt;

&lt;p&gt;Eu preciso de uma IA para auxiliar a revisar meus pull requests?&lt;/p&gt;

&lt;p&gt;Mas antes de responder esta pergunta devemos saber qual é o objetivo da organização ao estabelecer o procedimento de pull request, somente com um objetivo claro e quantificável, com por exemplo "Identificar e corrigir 30% dos bugs" ou "Garantir que pelo menos três desenvolvedores possam dar manutenções numa rotina" podemos definir a eficácia do processo. Definido o objetivo, podemos então estabelecer indicadores para medir a efetividade do processo, por exemplo, caso o objetivo seja a identificação dos bugs pode-se rastrear issues de bugs ao PR que as gerou, se o seu objetivo é garantir que mais desenvolvedores entendam uma rotina, pode-se verificar o tempo médio que um desenvolvedor utiliza para fazer manutenção em parte do código.&lt;/p&gt;

&lt;p&gt;A definição e rastreamento dos objetivos torna a adoção de uma IA como revisora de pull requests menos traumáticas, mas imaginando que a ferramenta irá alcançar o seu objetivo de aprovação de 63%, que conforme o site da ferramenta corresponde aos PR aprovados sem qualquer comentário, ou mesmo LGTM (Looks Good To Me), sua adoção é necessária?&lt;/p&gt;

&lt;p&gt;Deste ponto do artigo em diante trago apenas a minha opinião.&lt;/p&gt;

&lt;p&gt;Nem toda alteração precisa ser revisada. Acredito que a revisão de código é um dos mecanismos de revisão de produto que podem ser adotados por uma empresa, outras revisões de produto são o teste pela equipe de qualidade e a homologação pela equipe de suporte ou mesmo pelo cliente. Dependendo de algumas variáveis como o nível da alteração, a criticidade da rotina alterada e o nível do desenvolvedor, nem toda rotina precise passar por uma revisão de código. Obviamente este tipo de decisão não deve ficar ao sabor do momento, o ideal é que durante o planejamento a equipe decida quais alterações precisam de uma revisão mais detalhada e quais não.&lt;/p&gt;

&lt;p&gt;Sei que este pode ser o tipo de opinião impopular, mas deixar a decisão nas mãos da equipe é a melhor maneira de envolvê-los no processo, também é da equipe a responsabilidade sobre o número de bugs e sua correção.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>runnerhchallenge</category>
      <category>showdev</category>
      <category>autonomy</category>
    </item>
    <item>
      <title>Conversando com alienígenas, uma breve introdução ao Gherkin</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Thu, 16 Feb 2023 19:55:34 +0000</pubDate>
      <link>https://dev.to/becomex/conversando-com-alienigenas-uma-breve-introducao-ao-gherkin-2601</link>
      <guid>https://dev.to/becomex/conversando-com-alienigenas-uma-breve-introducao-ao-gherkin-2601</guid>
      <description>&lt;p&gt;Olá, pessoal! Espero encontrar todos bem. Hoje vocês aprenderão a se comunicar com uma espécie muito curiosa e intrigante que vive sobre a superfície do nosso pálido ponto azul - ou planeta Terra se você não for tão íntimo.&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%2Ffbw06xllrarhbdauditx.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%2Ffbw06xllrarhbdauditx.png" alt="Aliens" width="610" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas, antes de começarmos, preciso esclarecer uma coisa: se você começou a ler esse artigo esperando aprender a conversar com alienígenas de verdade, e talvez pensou que Gherkin fosse alguma máquina maluca de tradução de linguagens intergalácticas, detesto te desapontar, mas esse artigo não é bem sobre isso. Mas não desista de ler ele agora, prometo que esse material pode ser útil para você (mesmo se você realmente estiver querendo falar com aliens).&lt;/p&gt;

&lt;p&gt;Certo, então qual é a espécie intrigante a qual eu me referi no começo do artigo? E sobre o que é esse material afinal?&lt;/p&gt;

&lt;p&gt;No contexto deste artigo, quando falo em alienígenas, faço uma brincadeira com as pessoas da categoria a qual pertenço, me refiro a programadores e programadoras (devs) que em geral tem uma forma muito peculiar de interpretar o que as pessoas falam - darei exemplos e deixarei a analogia mais clara adiante. Esse artigo faz uma introdução a uma sintaxe, um modo de escrever determinado contexto, que elimina termos que possam não ser conhecidos por todos os interlocutores fazendo-o de uma forma declarativa, deste modo todos são capazes de compreender o contexto e qual é a mensagem a ser transmitida, aumentando assim a eficiência da comunicação entre os membros de um time em um ambiente de desenvolvimento de software, e claro, tornando mais fácil para nós desenvolvedores entender o que precisa ser feito. E o nome dessa estrutura mágica é Gherkin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problemática
&lt;/h2&gt;

&lt;p&gt;Vamos fazer o seguinte experimento mental: imagine que uma nave alienígena pouse na sua frente, dela sai um homenzinho verde com clara capacidade de manter uma comunicação complexa, mas você não entende um único som que esse visitante espacial emite, e ele também não possui nenhum conhecimento prévio sobre sua língua e cultura. O que você faria para tentar compreender o que nosso visitante está dizendo e como você ensinaria a ele nossa língua para que ele pudesse nos entender?&lt;/p&gt;

&lt;p&gt;A ideia de trazer esse experimento é causar a reflexão sobre como podemos nos comunicar com pessoas que não possuem o mesmo background que nós, que possuem outras ideias, onde aquilo que é óbvio para nós não é óbvio para nossos ouvintes. Nessa analogia, o homenzinho verde são os devs, e a questão é como um analista de negócio, gerente de produto ou qualquer outro estabelece contato conosco e nos solicita o desenvolvimento de uma nova funcionalidade. É claro que os papéis de marciano e terrestre podem ser facilmente invertidos, e que essa reflexão não vale apenas para comunicações onde devs estão envolvidos, mas também com qualquer pessoa, lembre-se que não é porque você fala a mesma linguagem que alguém, que não existirão ruídos na comunicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mais uma historinha
&lt;/h3&gt;

&lt;p&gt;Talvez você já tenha ouvido a piada onde alguém pede para um dev ir ao mercado com a seguinte instrução "Compre uma caixa de leite, e se tiver ovos traga dois" e assim o dev compra duas caixas de leite ao invés de uma caixa de leite e dois ovos como o solicitante queria. A piada pode ser engraçada, mas não é nada divertido quando essas confusões acontecem durante o desenvolvimento de um software, e a feature implementada não faz o que o solicitante esperava.&lt;/p&gt;

&lt;p&gt;Por essa razão, o modo como uma funcionalidade deve ser descrita é muito importante, não só para o programador, mas para que todos os envolvidos no processo de construção de um software tenham o mesmo entendimento do que deve ser feito.&lt;/p&gt;

&lt;p&gt;Só para constar, acho totalmente aceitável comprar duas caixas de leite considerando a instrução fornecida.&lt;/p&gt;

&lt;h2&gt;
  
  
  Falando sobre Gherkin
&lt;/h2&gt;

&lt;p&gt;Gherkin é um dos elementos presentes no BDD (Behavior Driven Development) e basicamente consiste em escrever cenários de forma padronizadas, baseadas nas regras de negócio e usando palavras-chave para compor os passos que devem ser seguidos até uma conclusão, sendo sempre escritas na terceira pessoa.&lt;br&gt;
Apesar de descrever as regras de negócio, o uso de palavras e termos que pertencem ao negócio deve ser evitado, é ideal que qualquer pessoa consiga ler e interpretar o que deve ser feito, mesmo que não possuam conhecimento de negócio. Em igual medida, termos técnicos e exemplo de codificação devem ser omitidos, essa especificação é o ponto onde todos os envolvidos na construção do software se encontram, sendo assim não pode haver termos que só um dos lados entenda.&lt;/p&gt;

&lt;p&gt;Além do motivo supracitado para não acrescentar códigos na solicitação de uma demanda, existe outra boa razão para não fazer isso, o maior valor que um desenvolvedor entrega não é quanto código ele escreve, mas os problemas que ele resolve, somos bons em resolver problemas e gostamos disso, entregar o problema resolvido para "apenas" escrever o código elimina a maior entrega de valor que podemos dar, além de nos matar vagarosamente.&lt;/p&gt;

&lt;p&gt;Os arquivos com a estrutura Gherkin são normalmente salvos com a extensão &lt;em&gt;feature&lt;/em&gt; e possuem notações iniciadas com cerquilha # para indicar por exemplo a linguagem das palavras-chave usadas naquele arquivo, a indentação do conteúdo é estruturado com espaços e quebra de linha, deste modo o aninhamento do conteúdo e as palavras-chave são identificadas. Essas especificações são especialmente importantes se você for manter esses conteúdos escritos em arquivos, mas nada o impede de usar a caixa de texto de algum sistema para manter esse conteúdo, a fim de usar a ideia e as palavras-chave do Gherkin nas definições de suas demandas no software de gerenciamento de projetos que sua empresa já usa.&lt;/p&gt;
&lt;h3&gt;
  
  
  Palavras-chave
&lt;/h3&gt;

&lt;p&gt;A lista abaixo apresenta as palavras-chave do Gherkin com uma breve descrição sobre seu objetivo&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature&lt;/strong&gt;: Descreve em níveis mais altos o propósito da funcionalidade e agrupa os diferentes cenários que podem existir;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background&lt;/strong&gt;: É o contexto, um conjunto inicial de steps que se repetem em todos os cenários da feature;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario&lt;/strong&gt; ou &lt;strong&gt;Example&lt;/strong&gt;: Descreve um exemplo concreto sobre a regra de negócio e é ou não seguido por steps, é possível incluir quantos steps desejar;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario Outline&lt;/strong&gt;: Usado para descrever um cenário que se repete alterando as entradas e saídas;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Usado para construir um conjunto de exemplos de entrada e saída para usar dentro do Scenario Outline;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;Given&lt;/strong&gt;: Descreve a condição inicial do cenário;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;When&lt;/strong&gt;: Descreve um evento que normalmente causa uma mudança;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;Then&lt;/strong&gt;: Descreve o resultado esperado após o evento;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;And&lt;/strong&gt;: Pode ser usado para concatenar de forma positiva sentenças dos steps anteriores;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;But&lt;/strong&gt;: Pode ser usado para acrescentar uma negativa de forma subsequente a um dos steps superiores;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Casos de testes escritos com Gherkin
&lt;/h3&gt;

&lt;p&gt;Para entendermos melhor a diferença entre simplesmente escrever a funcionalidade e escrevê-la usando Gherkin, que tal observamos um exemplo simples de login de usuário escritos das duas maneiras?&lt;/p&gt;

&lt;p&gt;Simplesmente descrevendo:&lt;br&gt;
Quando eu acessar o site e ir até a página de login e preencher o login a senha e clicar no botão de iniciar sessão, uma requisição a api do site deve ser feita transmitindo os dados preenchidos, se o resultado enviado pela api for positivo, uma mensagem de login efetuado com sucesso deve ser apresentada e o site deve me redirecionar para a página inicial do site mantendo minha sessão na memória do navegador.&lt;/p&gt;

&lt;p&gt;Usando o Gherkin:&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="na"&gt;Feature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Login de usuário&lt;/span&gt;

  &lt;span class="s"&gt;Scenario&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Login de usuário válido&lt;/span&gt;
    &lt;span class="s"&gt;Given que o usuário possua uma conta no site&lt;/span&gt;
    &lt;span class="s"&gt;And acesse a página de login&lt;/span&gt;
    &lt;span class="s"&gt;And preencha corretamente os dados de acesso&lt;/span&gt;
    &lt;span class="s"&gt;When ele acionar o botão de entrar no sistema&lt;/span&gt;
    &lt;span class="s"&gt;Then uma mensagem de sucesso deve ser apresentada&lt;/span&gt;
    &lt;span class="s"&gt;And ele deve ser direcionado logado a página inicial do site&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como se pode observar, o modelo escrito com Gherkin é muito mais claro e omite qualquer detalhe técnico do desenvolvimento. Que tal darmos uma olhada em outro exemplo, agora usando as palavras-chave faltantes?&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="na"&gt;Feature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Café da tarde&lt;/span&gt;

&lt;span class="na"&gt;Background&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;Given que os escritores de artigos sentem fome&lt;/span&gt;

&lt;span class="na"&gt;Scenario Outline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Comendo fatias de bolo&lt;/span&gt;
  &lt;span class="s"&gt;Given que existe &amp;lt;inicial&amp;gt; fatias de bolo&lt;/span&gt;
  &lt;span class="s"&gt;When for comido &amp;lt;comido&amp;gt; fatias de bolo&lt;/span&gt;
  &lt;span class="s"&gt;Then deve restar &amp;lt;restante&amp;gt; fatias de bolo&lt;/span&gt;

  &lt;span class="s"&gt;Examples&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="err"&gt;inicial&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;comido&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;restante&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;|    10   |    3   |     7    |&lt;/span&gt;
    &lt;span class="s"&gt;|     5   |    5   |     0    |&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apesar dos exemplos modestos, acredito que seja possível compreender a ideia geral. Alguém poderia dizer que esse modelo adiciona mais trabalho na escrita dos cenários, ou mesmo que essa divisão parece infantil e que um texto corrido teria o mesmo efeito. Qualquer quantia de tempo acrescido na criação das descrições das atividades seria recuperada, uma vez que seria poupando tempo de manutenção e correções por conta do desentendimento quanto ao objetivo da função. Quanto a divisão parecer infantil, pense que você está escrevendo cenários para pessoas que não tem o mesmo conhecimento de negócio que você, imagine aquele marciano na sua frente e tente explicar para ele o que precisa ser feito...&lt;/p&gt;

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

&lt;p&gt;Escrever os cenários com Gherkin é incrivelmente simples, o fato de ter poucas palavras-chave torna o modelo muito fácil de ser aprendido, e após escrever poucos cenários não é mais necessário pesquisar exemplos para se basear.&lt;/p&gt;

&lt;p&gt;Além de ser fácil, esse modelo fornece uma estrutura de escrita que quando é bem usada, diminui consideravelmente os ruídos e mal-entendidos entre o que o solicitante precisar e o que é implementado de fato.&lt;/p&gt;

&lt;p&gt;Por hoje é tudo pessoal, espero que tenham se divertido com a leitura e tenham se interessado por aprender um pouco mais sobre Gherkin, não deixe de conferir as fontes deste material.&lt;/p&gt;

&lt;p&gt;Ah, e se encontrar um alien por aí, diga que eu mandei um "Oi!".&lt;/p&gt;

&lt;h2&gt;
  
  
  Fontes:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cucumber.io/docs/gherkin/reference/" rel="noopener noreferrer"&gt;https://cucumber.io/docs/gherkin/reference/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/revista-tspi/gherkin-o-dia-em-que-entendi-que-estava-escrevendo-errado-220a84520819" rel="noopener noreferrer"&gt;https://medium.com/revista-tspi/gherkin-o-dia-em-que-entendi-que-estava-escrevendo-errado-220a84520819&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
  </channel>
</rss>
