<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: DEVz Wiz</title>
    <description>The latest articles on Forem by DEVz Wiz (@devzwiz).</description>
    <link>https://forem.com/devzwiz</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%2F2646%2F4054ca95-31a5-4499-87e5-9d01726c16c2.png</url>
      <title>Forem: DEVz Wiz</title>
      <link>https://forem.com/devzwiz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devzwiz"/>
    <language>en</language>
    <item>
      <title>Devops #1 - Qualidade x Tempo</title>
      <dc:creator>Zama Bandeira Braga</dc:creator>
      <pubDate>Fri, 09 Jul 2021 13:55:25 +0000</pubDate>
      <link>https://forem.com/devzwiz/devops-1-qualidade-x-tempo-5dpa</link>
      <guid>https://forem.com/devzwiz/devops-1-qualidade-x-tempo-5dpa</guid>
      <description>&lt;p&gt;O desenvolvimento de software e composto por algumas diferenças históricas, desenvolvimento x operação, qualidade x tempo, expectativa x realidade.&lt;/p&gt;

&lt;p&gt;Quando me pergunto sobre a qualidade de um software, me vem a imagem de uma lista de testes executados e todos verdinhos, já para Willian E. Deming em seu livro &lt;a href="https://www.amazon.com.br/Qualidade-Administracao-William-Edwards-Deming/dp/8585238151"&gt;Qualidade: revolução da administração&lt;/a&gt; afirma que, a qualidade tem muitas escalas, por exemplo, um livro de qualidade é determinado pela legibilidade, papel, tamanho, inexistência de erros, ou seja, o leitor deseja encontrar no livro cultura e entretenimento, enquanto a editora deseja encontrar nele, boa oportunidade de venda. A avaliação do que é qualidade dependeria, portanto, das escalas de valor determinadas por cada entidade.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://asq.org/quality-resources/iso-9000"&gt;ISO 900&lt;/a&gt; define a qualidade como a totalidade de características de uma entidade que lhe confere a capacidade de satisfazer as necessidades explícitas e implícitas, onde qualidades explícitas são aquelas que o produtor de software garante, explicitamente, ao cliente; enquanto as qualidades implícitas são aquelas subjetivamente esperadas pelo cliente.&lt;br&gt;
As definições de Deming e da ISO convergem para necessidade de percebe-se a existência de duas entidades confrontantes para definição da qualidade, o desenvolvedor como entidade deseja um código entendível, padronizado, de fácil manutenção e que possibilite evoluções. O negócio por sua vez deseja um desenvolvimento rápido e que gere o menor número de reclamações dos clientes. &lt;/p&gt;

&lt;p&gt;E como conseguir isso? Como conseguir criar um processo de software que atenda o dev como o negócio? Se alguém souber como me ensina. &lt;/p&gt;

&lt;p&gt;As necessidades da área técnica para o desenvolvimento são atendidas com a adoção da filosofia de teste, seja TDD, BDD, etc. As necessidades da área negocial são atendidas também por garantir um menor impacto ao cliente, evitando uma cascata de incidentes após corrigir um, isso tudo porque é possível identificar todo o impacto de uma correção ou evolução da aplicação. &lt;/p&gt;

&lt;p&gt;E o Tempo? O teste resolve os questionamentos voltados para o bem estar da aplicação, e não a variável tempo, que é importante para o negócio. Agora inicia-se a batalha do desenvolvimento x tempo. Como garantir que todos os requisitos da qualidade técnica foram atendidos em um tempo curto de desenvolvimento?&lt;/p&gt;

&lt;p&gt;E comum ouvir durante uma sala de guerra, "não tivemos tempo de fazer os testes”, não concordo com essa sentença e acho errado vender que é preciso ter tempo para fazer o teste. O teste e a forma de garantir a qualidade da solução desenvolvida, se a minha solução foi desenvolvida em 72 horas (eita lasqueira) os testes são para garantir o que foi desenvolvido nessas 72 horas, nada mais.&lt;/p&gt;

&lt;p&gt;A partir do momento em que você inicia um desenvolvimento o orientado a testes, o teste é o seu desenvolvimento. Ele faz parte da sua solução. &lt;/p&gt;

&lt;p&gt;Desenvolvedor, pare de falar que não tem tempo para testar! Se você tem tempo de subir a aplicação e consultar via Postman você teve tempo de fazer o teste, o tempo que você abre e fecha a tela do Postman, era um teste desenvolvido. &lt;/p&gt;

&lt;p&gt;Negócio, pare de comparar a qualidade de produtos desenvolvidos em diferentes tempos e jogar todas as features como prioritárias! Não faz sentido comparar a qualidade de uma solução desenvolvida em 200 horas com uma solução desenvolvida em 72 horas. &lt;/p&gt;

&lt;p&gt;O processo de desenvolvimento de software de qualidade e um gerenciamento das expectativas de tempo com a expectativa de tecnologia. Sommerville diz que, se o sistema é legado você deve evitar ao máximo evoluí-lo, pois ele é um caos! Você não conseguirá rastrear o que é impactado com a alteração, logo se eu não consigo rastrear os impactos de uma alteração, quer dizer que ele não possui requisitos de testes que me possibilitem esse rastreio, levando a conclusão que se a solução não possui teste, ela e uma solução legada. &lt;/p&gt;

&lt;p&gt;Hoje você desenvolve uma solução legada ou um produto de qualidade?&lt;/p&gt;

</description>
      <category>devops</category>
      <category>teste</category>
      <category>tdd</category>
    </item>
    <item>
      <title>Stoplight/Prism-CLI - Acelerando o desenvolvimento e aumentando a integração</title>
      <dc:creator>Bernardo Costa Nascimento</dc:creator>
      <pubDate>Thu, 25 Feb 2021 19:29:22 +0000</pubDate>
      <link>https://forem.com/devzwiz/stoplight-prism-cli-acelerando-o-desenvolvimento-e-aumentando-a-integracao-2ghp</link>
      <guid>https://forem.com/devzwiz/stoplight-prism-cli-acelerando-o-desenvolvimento-e-aumentando-a-integracao-2ghp</guid>
      <description>&lt;p&gt;Ao desenvolver novas APIs, muitas vezes os desenvolvedores (&lt;em&gt;devs&lt;/em&gt;) &lt;em&gt;front-end&lt;/em&gt; precisam &lt;em&gt;mockar&lt;/em&gt; dados para criar e demonstrar os &lt;em&gt;layouts&lt;/em&gt; que estão desenvolvendo. É uma atividade que demanda tempo e, eventualmente, o código será jogado fora. No &lt;em&gt;back-end&lt;/em&gt;, as &lt;em&gt;features&lt;/em&gt; podem demorar algum tempo para estarem disponíveis e, em caso de mudanças, o &lt;em&gt;dev&lt;/em&gt; terá de alterar o código, atualizar os testes, realizar uma nova build e um novo &lt;em&gt;deploy&lt;/em&gt;, atividades que demandam tempo. Como podemos otimizar as tarefas do &lt;em&gt;back-end&lt;/em&gt; e &lt;em&gt;front-end&lt;/em&gt; para que não haja código &lt;em&gt;mockado&lt;/em&gt; e novo ciclo de &lt;em&gt;dev-build-deploy&lt;/em&gt;? Podemos utilizar a ferramenta Stoplight/Prism-CLI.&lt;/p&gt;

&lt;p&gt;Prism permite que &lt;em&gt;devs&lt;/em&gt; criem &lt;em&gt;&lt;strong&gt;mocks&lt;/strong&gt;&lt;/em&gt; da API com uma base mínima de código no &lt;em&gt;back-end&lt;/em&gt;, fazendo com que não seja necessária a criação de &lt;em&gt;mocks&lt;/em&gt; – que serão, eventualmente, descartados – no &lt;em&gt;front-end&lt;/em&gt;. Ainda, torna possível testar o contrato da API, por meio de um &lt;em&gt;&lt;strong&gt;proxy&lt;/strong&gt;&lt;/em&gt;, auxiliando na diminuição de erros após mudanças no código. Por fim, como a ferramenta usa o OpenAPI como base para criação dos &lt;em&gt;mocks&lt;/em&gt; e &lt;em&gt;proxies&lt;/em&gt;, sua utilização auxilia na criação de documentações mais robustas para as APIs desenvolvidas. Este artigo abordará como utilizar a ferramenta em seus dois modos – &lt;em&gt;mock&lt;/em&gt; e &lt;em&gt;proxy&lt;/em&gt; – para auxiliar, acelerar e integrar o desenvolvimento &lt;em&gt;front-end&lt;/em&gt; e &lt;em&gt;back-end&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbh6zs1f1amp3ykh0w88.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%2Fhbh6zs1f1amp3ykh0w88.png" alt="Prism exemplo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Sumário
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Instalação do @stoplight/prism-cli&lt;/li&gt;
&lt;li&gt;Código &lt;em&gt;back-end&lt;/em&gt; &amp;amp; &lt;em&gt;OpenAPI Documentation&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Prism &lt;em&gt;Mock Server&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Prism &lt;em&gt;Proxy Server&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Instalação do @stoplight/prism-cli
&lt;/h2&gt;

&lt;p&gt;Antes de mais nada, precisamos instalar a ferramenta Prism em nosso ambiente de desenvolvimento. A documentação prevê três formas de instalação, mas por motivos de simplicidade, abordaremos apenas o primeiro, que utiliza o NPM para realizar a instalação. Dessa forma, instale a ferramenta utilizando o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Usando NPM&lt;/span&gt;
npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @stoplight/prism-cli

&lt;span class="c"&gt;# Usando Yarn&lt;/span&gt;
yarn add global @stoplight/prism-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Código &lt;em&gt;back-end&lt;/em&gt; &amp;amp; &lt;em&gt;OpenAPI Documentation&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Com o Prism instalado, podemos iniciar o código &lt;em&gt;back-end&lt;/em&gt;. O &lt;a href="https://github.com/wizsolucoes/api-wiz-template" rel="noopener noreferrer"&gt;&lt;em&gt;template&lt;/em&gt; de APIs da Wiz&lt;/a&gt; já traz um exemplo básico de arquitetura de desenvolvimento de uma API e possui o OpenAPI instalado por &lt;em&gt;default&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As rotas do &lt;em&gt;template&lt;/em&gt; possuem algumas &lt;em&gt;tags&lt;/em&gt; XML e &lt;em&gt;Annotations&lt;/em&gt;, que formarão o JSON responsável por gerar a documentação da API. Na Figura 1, a rota apresenta uma descrição (&lt;em&gt;summary&lt;/em&gt;), três códigos de resposta (&lt;em&gt;response&lt;/em&gt;) e três &lt;em&gt;schemas&lt;/em&gt; para os códigos de respostas gerados (&lt;em&gt;ProducesResponseType&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91wdeo6l9sw2p2s2iwpz.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%2F91wdeo6l9sw2p2s2iwpz.png" alt="Tags XML e Annotations para uma rota da API"&gt;&lt;/a&gt;&lt;br&gt;
Figura 1 - &lt;em&gt;Tags&lt;/em&gt; XML e &lt;em&gt;Annotations&lt;/em&gt; para uma rota da API.&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%2F81tw2x1wcwaz1upjzykh.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%2F81tw2x1wcwaz1upjzykh.png" alt="Documentação gerada pelas tags XML e Annotations no código back-end"&gt;&lt;/a&gt;&lt;br&gt;
Figura 2 - Documentação gerada pelas &lt;em&gt;tags&lt;/em&gt; XML e &lt;em&gt;Annotations&lt;/em&gt; no código &lt;em&gt;back-end&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Se pararmos aqui, os exemplos de requisição e resposta, gerados pelo OpenAPI, serão genéricos, como visto na Figura 3.&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%2Fyh0m2peqil8seq5chlpu.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%2Fyh0m2peqil8seq5chlpu.png" alt="Exemplo de resposta genérica gerada pelo OpenAPI"&gt;&lt;/a&gt;&lt;br&gt;
Figura 3 - Exemplo de resposta genérica gerada pelo OpenAPI.&lt;/p&gt;

&lt;p&gt;O Prism é capaz de gerar informações aleatórias para compor as respostas, no entanto como veremos mais adiante, é possível ter maior controle sobre o conteúdo das respostas e, por consequência, definir exemplos que documentarão melhor a API em desenvolvimento.&lt;/p&gt;

&lt;p&gt;Para isso, adicionaremos &lt;em&gt;tags&lt;/em&gt; XML e &lt;em&gt;Annotations&lt;/em&gt; nas &lt;em&gt;ViewModels&lt;/em&gt; da API e, caso não existam &lt;em&gt;ViewModels&lt;/em&gt; específicas para erros, criaremos classes de exemplo para compor a documentação. A Figura 4 demonstra algumas das &lt;em&gt;tags&lt;/em&gt; e &lt;em&gt;Annotations&lt;/em&gt; utilizadas para melhor documentar a API. É importante ressaltar que, no caso da &lt;em&gt;Annotation&lt;/em&gt; &lt;em&gt;JsonSchemaExtensionData&lt;/em&gt;, é necessária a instalação do pacote &lt;em&gt;NjsonSchema.Annotations&lt;/em&gt;, que permite adicionar informações que não seriam identificadas pelo OpenAPI.&lt;/p&gt;

&lt;p&gt;Ao analisar a Figura 4, as &lt;em&gt;tags&lt;/em&gt; &lt;em&gt;example&lt;/em&gt; e &lt;em&gt;minimum&lt;/em&gt; provavelmente são familiares, pois estão previstas na especificação do OpenAPI. Mas e a &lt;em&gt;tag&lt;/em&gt; &lt;em&gt;x-faker&lt;/em&gt;?&lt;/p&gt;
&lt;h2&gt;
  
  
  Prism &lt;em&gt;Mock Server&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Como dito anteriormente, o Prism é capaz de gerar &lt;em&gt;mocks&lt;/em&gt; de respostas para as requisições feitas ao servidor gerado a partir da descrição do OpenAPI. Essas respostas podem ser estáticas ou dinâmicas. Vamos começar pelas respostas estáticas.&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%2Frgqqe3usa9d5mzsh7bnk.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%2Frgqqe3usa9d5mzsh7bnk.png" alt="Exemplos de tags para documentação no OpenAPI"&gt;&lt;/a&gt;&lt;br&gt;
Figura 4 - Exemplos de &lt;em&gt;tags&lt;/em&gt; para documentação no OpenAPI.&lt;/p&gt;

&lt;p&gt;As respostas estáticas são produzidas a partir dos exemplos informados nas &lt;em&gt;ViewModels&lt;/em&gt; da API e serão o default ao iniciar o servidor por meio do comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prism mock http://localhost:5001/swagger/v1/swagger.json

&lt;span class="c"&gt;## Ou&lt;/span&gt;

prism mock path/to/descriptor.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao iniciar o &lt;em&gt;mock&lt;/em&gt; server dessa maneira, todas as repostas serão baseadas nos exemplos fornecidos. Caso não haja um exemplo, o Prism gera respostas aleatórias com base nos tipos esperados.&lt;/p&gt;

&lt;p&gt;No entanto, a utilização das respostas estáticas pode gerar um viés no &lt;em&gt;front-end&lt;/em&gt;, uma vez que as respostas, em um cenário real, são variadas. Então, como podemos gerar respostas aleatórias, mas com algum controle sobre seu conteúdo? É aqui que a &lt;em&gt;tag&lt;/em&gt; &lt;em&gt;x-faker&lt;/em&gt; vai nos ajudar.&lt;/p&gt;

&lt;p&gt;Por baixo dos panos, o Prism utiliza a biblioteca Faker.js para gerar os dados de forma aleatória e, acessando a documentação da biblioteca, vemos que existem dezenas de métodos capazes de gerar respostas aleatórias para diversos contextos. Assim, podemos utilizar a &lt;em&gt;tag&lt;/em&gt; &lt;em&gt;x-faker&lt;/em&gt;, combinada com os métodos disponibilizados pela API, para imprimir contexto nas respostas. Na Figura 4, por exemplo, o “CEP” é gerado com base no método &lt;em&gt;&lt;strong&gt;address.zipCode&lt;/strong&gt;&lt;/em&gt; e, portanto, toda resposta não estática vai gerar um &lt;em&gt;zip code&lt;/em&gt; aleatório.&lt;/p&gt;

&lt;p&gt;Mas ainda fica uma dúvida: caso exista um exemplo, como o &lt;em&gt;mock&lt;/em&gt; server pode gerar respostas dinâmicas? Para isso, basta iniciar o &lt;em&gt;mock&lt;/em&gt; server com a &lt;em&gt;flag&lt;/em&gt; “-d” ou “--dynamic”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prism mock &lt;span class="nt"&gt;-d&lt;/span&gt; http://localhost:5001/swagger/v1/swagger.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ainda, é possível determinar que apenas uma rota específica gere respostas estáticas ou dinâmicas. Para isso, basta passar a utilizar o header “Prefer dynamic=true/false” em suas requisições. O mesmo header pode ser utilizado mais de uma vez e pode ajudar a controlar, também, o código da resposta gerada. Por exemplo, caso o &lt;em&gt;front-end&lt;/em&gt; queira testar um cenário de erro na resposta da API, ele pode criar uma requisição com contrato inválido (faltando um campo obrigatório, por exemplo) ou pode utilizar o header “Prefer code=400” para gerar uma resposta com código 400 (&lt;em&gt;Bad Request&lt;/em&gt;) por parte do &lt;em&gt;mock&lt;/em&gt; server. Para mais exemplos sobre o header, utilize a documentação do Prism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prism &lt;em&gt;Proxy Server&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Utilizando o &lt;em&gt;mock&lt;/em&gt; server, os &lt;em&gt;devs&lt;/em&gt; &lt;em&gt;front-end&lt;/em&gt; podem ir desenvolvendo os sites sem a necessidade de um &lt;em&gt;back-end&lt;/em&gt; funcional, sendo necessário trocar apenas o endereço base das requisições pelo endereço da API funcional, uma vez que esta esteja disponível (i.e. trocar &lt;a href="http://localhost:4010/api/vX/" rel="noopener noreferrer"&gt;http://localhost:4010/api/vX/&lt;/a&gt; por https://&amp;lt;projeto&amp;gt;-hml-api.azurewebsites.net/api/vX).&lt;/p&gt;

&lt;p&gt;Apesar disso, pequenas mudanças ou erros podem ter ocorrido – tanto no &lt;em&gt;front&lt;/em&gt;, quanto no &lt;em&gt;back&lt;/em&gt; – e as requisições ou os contratos não estarem de acordo com o esperado. Para testar os contratos, o Prism dispõe de um &lt;em&gt;proxy server&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;proxy server&lt;/em&gt; utiliza um descritor do OpenAPI e o endereço da API para validar os contratos de requisição e resposta. Dessa maneira, o usuário pode realizar chamadas à API e verificar se todas as requisições feitas e as respostas geradas batem com o que está definido no descritor, garantido que, uma vez que a API vá para produção, &lt;em&gt;front&lt;/em&gt; e &lt;em&gt;back&lt;/em&gt; não possuam erros de contrato. O &lt;em&gt;proxy server&lt;/em&gt; pode ser iniciado pelo comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prism proxy path/to/descriptor.json https://&amp;lt;projeto&amp;gt;-hml-api.azurewebsites.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para mais informações sobre o &lt;em&gt;proxy server&lt;/em&gt;, acesse a documentação do Prism.&lt;/p&gt;

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

&lt;p&gt;A ferramenta Prism server para auxiliar a abordagem “&lt;em&gt;design-first&lt;/em&gt;” para o desenvolvimento de APIs por meio do &lt;em&gt;mock&lt;/em&gt; e, uma vez que todas as informações e preparativos estejam nas mãos do time de &lt;em&gt;back-end&lt;/em&gt;, o proxy permite testar os contratos criados entre &lt;em&gt;front&lt;/em&gt; e &lt;em&gt;back&lt;/em&gt;.&lt;br&gt;
    Sendo assim, o Prism pode auxiliar na integração entre &lt;em&gt;devs&lt;/em&gt; &lt;em&gt;front&lt;/em&gt; e &lt;em&gt;back&lt;/em&gt;, que terão de chegar a um consenso sobre os contratos, permite que o front desenvolva sem a necessidade de uma API e auxilia o &lt;em&gt;back&lt;/em&gt; em uma melhor documentação da API em desenvolvimento.&lt;/p&gt;

</description>
      <category>api</category>
      <category>documentation</category>
      <category>frontend</category>
      <category>backend</category>
    </item>
    <item>
      <title>GC: Otimizando para o ambiente do Azure</title>
      <dc:creator>Pode me chamar de Juscélio Reis</dc:creator>
      <pubDate>Sun, 07 Feb 2021 15:24:40 +0000</pubDate>
      <link>https://forem.com/devzwiz/gc-otimizando-para-o-ambiente-do-azure-4mkp</link>
      <guid>https://forem.com/devzwiz/gc-otimizando-para-o-ambiente-do-azure-4mkp</guid>
      <description>&lt;p&gt;Neste artigo, pretendo abordar um assunto complicado e que pode ser usado para melhorar nossas aplicações hospedados na nuvem da Microsoft Azure. Vou abordar o que exatamente acontece durante a coleta de lixo (GC) e como diferentes modos de GC podem afetar significativamente o desempenho do aplicativo. Mas antes vamos entender qual o ambiente que estamos executando nossas aplicações.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure
&lt;/h2&gt;

&lt;p&gt;O que mais consumimos do Azure aqui na Wiz é o serviço de Aplicativo, ou se preferir chamar App Service. Esse serviço quando criado é composto de alguns nomes ou outros serviços. Sendo eles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;App Service Plan (Plano de Serviço de Aplicativo)&lt;/strong&gt;: Um Plano de Serviço de Aplicativo consiste nas máquinas virtuais alocadas que hospedarão os Serviços de Aplicativo do Azure. Possui vários níveis, do Gratuito ao Premium, seu orçamento é o limite. O Plano de Serviço de Aplicativo define a região do servidor físico onde seu aplicativo será hospedado e a quantidade de armazenamento, &lt;strong&gt;RAM&lt;/strong&gt; e &lt;strong&gt;CPU&lt;/strong&gt; que os servidores físicos terão.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;App Service (Serviço de Aplicativo)&lt;/strong&gt;: O Serviço de Aplicativo do Azure é um serviço baseado em HTTP para hospedar aplicativos da web, APIs REST e back-ends móveis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Group (grupo de recursos)&lt;/strong&gt;: Um grupo de recursos é um conjunto que contém recursos relacionados para uma solução do Azure. O grupo de recursos pode incluir todos os recursos da solução ou apenas os recursos que você deseja gerenciar como um grupo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora que temos a nomenclatura do Azure para os serviços de APIs, vamos observas os planos de serviço, ou como aprendemos, vamos olhar nas opções do &lt;em&gt;App Service Plan&lt;/em&gt;. Podemos dividir esse plano de serviço em três categorias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Computação compartilhada&lt;/em&gt;: &lt;em&gt;Free&lt;/em&gt; ou &lt;em&gt;F1&lt;/em&gt; e &lt;em&gt;Shared&lt;/em&gt;, as duas camadas de base, executa um aplicativo na mesma VM do Azure que outros aplicativos de serviço de aplicativo, incluindo aplicativos de outros clientes. Essas camadas alocam cotas de CPU para cada aplicativo executado nos recursos compartilhados, e os recursos não podem ser escalonados. Esse plano possui um limite de tempo e não permite a opção de configurar as apis em dotnet como 64 bits. &lt;strong&gt;Esse plano é um grande problema para nossas apis, pois a combinação do dotnet core 3.1 com uma configuração de 32 bits vai resultar em erro de estouro de memória, em outras palavras não usem em ambiente de homologação ou produção&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Computação dedicada&lt;/em&gt;: as camadas Basic, Standard, Premium, PremiumV2 e PremiumV3 executam aplicativos em VMs do Azure dedicadas. Somente aplicativos no mesmo &lt;em&gt;App Service Plan&lt;/em&gt; &lt;strong&gt;compartilham os mesmos recursos de computação&lt;/strong&gt;. Quanto mais alto o nível, mais instâncias de VM estão disponíveis para você escalar horizontalmente. Essa é a opção que usamos em homologação e produção, em sua grande maioria usamos o plano &lt;em&gt;S1&lt;/em&gt; ou &lt;em&gt;Standard 1&lt;/em&gt;, em alguns casos usamos o plano &lt;em&gt;B1&lt;/em&gt; ou &lt;em&gt;Basic&lt;/em&gt;, &lt;strong&gt;lembrando que não é recomendado pela Microsoft a utilização do plano Basic para produção&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Isolado&lt;/em&gt;: esta camada executa VMs do Azure dedicadas em Redes Virtuais do Azure dedicadas. Ele fornece isolamento de rede além do isolamento de computação para seus aplicativos. Ele fornece os recursos de expansão máxima. No momento vamos ignorar esse modo aqui.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Preste atenção aqui&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O plano B1 possui 1 núcleo de CPU e 1.75 GB de ram, pode receber até 3 instancias de aplicativos, além de outras limitações do plano &lt;em&gt;Basic&lt;/em&gt;. &lt;a href="https://azure.microsoft.com/pt-br/pricing/details/app-service/windows/"&gt;Mais informação aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O plano S1 possui 1 núcleo de CPU e 1.75 GB de ram, mas pode receber até 10 instancias de aplicativos, além de outras limitações do plano &lt;em&gt;Standard&lt;/em&gt;. &lt;a href="https://azure.microsoft.com/pt-br/pricing/details/app-service/windows/"&gt;Mais informação aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Bom agora podemos voltar ao tema principal desse artigo &lt;em&gt;garbage collection&lt;/em&gt; ou GC pros íntimos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Garbage Collection
&lt;/h2&gt;

&lt;p&gt;Vou colocar um pequeno resumo do GC aqui, só para entender qual o seu papel no nosso ambiente computacional. Mas será um breve resumo, mais informação ler esse &lt;a href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#ephemeral-generations-and-segments"&gt;artigo aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O garbage collection (GC) atua como um &lt;em&gt;gerenciador de memória automático&lt;/em&gt;. O garbage collection gerencia a alocação e liberação de memória para um aplicativo. O gerenciamento automático de memória pode eliminar problemas comuns, como esquecer de liberar um objeto e causar um vazamento de memória ou tentar acessar a memória de um objeto que já foi liberado.&lt;/p&gt;

&lt;p&gt;A coleta de lixo ocorre quando uma das seguintes condições é verdadeira:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;O sistema está com pouca memória física. Isso é detectado pela notificação de memória insuficiente do sistema operacional ou memória insuficiente, conforme indicado pelo host.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A memória usada por objetos alocados no heap gerenciado ultrapassa um limite aceitável. Este limite é continuamente ajustado conforme o processo é executado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O método GC.Collect é chamado. Em quase todos os casos, &lt;strong&gt;você não precisa chamar esse método&lt;/strong&gt;, porque o coletor de lixo é executado continuamente. &lt;strong&gt;Este método é usado principalmente para situações e testes únicos&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O algoritmo GC é baseado em várias premissas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;É mais rápido compactar a memória para uma parte do heap gerenciado do que para todo o heap gerenciado.&lt;/li&gt;
&lt;li&gt;Objetos mais novos têm vida útil mais curta e objetos mais antigos têm vida útil mais longa.&lt;/li&gt;
&lt;li&gt;Objetos mais novos tendem a estar relacionados entre si e acessados pelo aplicativo ao mesmo tempo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como vemos a estratégia do GC é dividir o heap em partes considerando a idade dos objetos para otimizar o desempenho, o heap gerenciado é dividido em três gerações, 0, 1 e 2.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Geração 0: Esta é a geração mais jovem e contém objetos de curta duração. Um exemplo de objeto de vida curta é uma variável temporária. A coleta de lixo ocorre com mais frequência nesta geração.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Geração 1: Esta geração contém objetos de vida curta e serve como um buffer entre objetos de vida curta e objetos de vida longa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Geração 2: Esta geração contém objetos de vida longa. Um exemplo de objeto de longa duração é um objeto em um aplicativo de servidor que contém dados estáticos que estão ativos durante o processo. &lt;strong&gt;Mais um motivo para nunca encher nossa aplicação com objetos estáticos&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Objetos que não são recuperados em uma coleta de lixo são conhecidos como sobreviventes e são promovidos para a próxima geração:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Os objetos que sobrevivem a uma coleta de lixo da geração 0 são promovidos para a geração 1.&lt;/li&gt;
&lt;li&gt;Os objetos que sobrevivem a uma coleta de lixo da geração 1 são promovidos para a geração 2.&lt;/li&gt;
&lt;li&gt;Os objetos que sobrevivem a uma coleta de lixo da geração 2 permanecem na geração 2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Até aqui podemos entender que os objetos da geração 0 e 1 são os mais voláteis ou como está na documentação são objetos efêmeros. Já os objetos da geração 2 são mais permanentes então não faz tanto sentido fazer uma coleta de lixo completa, podemos focar mais nas gerações 0 e 1 que vamos obter mais sucesso. &lt;strong&gt;Mais um motivo para evitar a utilização de objetos estáticos e de tentar chamar o GC.Collect manualmente&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Estamos chegando na parte de otimização, até aqui foi um grande resumo do resumo para começar o processo de otimização. *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;O tamanho do segmento efêmero varia dependendo se um sistema é de 32 ou 64 bits e do tipo de coletor de lixo que está executando (Workstation ou Server GC). A tabela a seguir mostra os tamanhos padrão do segmento efêmero.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workstation/server GC&lt;/th&gt;
&lt;th&gt;32-bit&lt;/th&gt;
&lt;th&gt;64-bit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Workstation GC&lt;/td&gt;
&lt;td&gt;16 MB&lt;/td&gt;
&lt;td&gt;256 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server GC&lt;/td&gt;
&lt;td&gt;64 MB&lt;/td&gt;
&lt;td&gt;4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server GC with &amp;gt; 4 logical CPUs&lt;/td&gt;
&lt;td&gt;32 MB&lt;/td&gt;
&lt;td&gt;2 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server GC with &amp;gt; 8 logical CPUs&lt;/td&gt;
&lt;td&gt;16 MB&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Acabamos de saber que o existem dois tipos de GC, um chamado Workstation GC e outro chamado Server GC. Bora entender esses caras, pois aqui está a chave para a otimização das nossas APIs que estão executando no Azure. Se não entendeu olha o tamanho que elas possuem no ambiente de 64 bits e compara com o tamanho do &lt;em&gt;App Service Plan&lt;/em&gt; B1 e S1, vai perceber que a matemática não vai bater.&lt;/p&gt;

&lt;p&gt;O GC é inteligente e pode funcionar em uma ampla variedade de cenários. No entanto, podemos definir o tipo de GC com base nas características da carga de trabalho, em outras palavras de acordo com o &lt;em&gt;App Service Plan&lt;/em&gt;. O dotnet fornece os seguintes tipos de GC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Workstation: GC da estação de trabalho, que é projetada para aplicativos cliente. É o padrão do GC para aplicativos independentes. Para aplicativos hospedados, por exemplo, aqueles hospedados pelo ASP.NET, o host determina o padrão do GC. Vai um &lt;em&gt;spoiler&lt;/em&gt; vai ser o tipo Server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server: GC que se destina a aplicativos de servidor que precisam de alto rendimento e escalabilidade.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Otimização
&lt;/h2&gt;

&lt;p&gt;Aqui é onde vou citar o blog da microsoft, a visão que eles possuíam do ambiente de hospedagem das aplicações dotnet:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep in mind that it’s very common to run only one server process on a dedicated machine so you don’t get into this situation. &lt;br&gt;
-- Maoni, &lt;a href="https://devblogs.microsoft.com/dotnet/workstation-gc-for-server-applications/"&gt;Workstation GC for server applications?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Não é o que estamos utilizando no contexto atual, usamos servidores com 1 núcleo e 1.75GB de ram para hospedar de 3 a 10 aplicações. Essa é a questão!!! Precisamos mudar o padrão e utilizar como uma aplicação que vai funcionar na máquina do cliente em outras palavras precisamos sair do Server GC para o Workstation GC. Mas ao começar essa otimização precisamos alterar uma tag no &lt;em&gt;.Api.csproj, vamos colocar a tag *ServerGarbageCollection&lt;/em&gt; como &lt;em&gt;false&lt;/em&gt;. &lt;a href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/workstation-server-gc"&gt;Mais informação aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Porem ao alterar essa tag precisamos alterar outra &lt;em&gt;ConcurrentGarbageCollection&lt;/em&gt; para &lt;em&gt;false&lt;/em&gt;, se você está executando várias instâncias de aplicativo, considere o uso do Workstation GC com a coleta de lixo simultânea desabilitada, &lt;em&gt;ConcurrentGarbageCollection false&lt;/em&gt;. Isso resultará em menos troca de contexto, o que pode melhorar o desempenho.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk.Web"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;netcoreapp3.1&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;AspNetCoreHostingModel&amp;gt;&lt;/span&gt;InProcess&lt;span class="nt"&gt;&amp;lt;/AspNetCoreHostingModel&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GenerateDocumentationFile&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/GenerateDocumentationFile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;IncludeOpenAPIAnalyzers&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/IncludeOpenAPIAnalyzers&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ServerGarbageCollection&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/ServerGarbageCollection&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ConcurrentGarbageCollection&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/ConcurrentGarbageCollection&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Fiz um teste e você pode ver como a combinação de &lt;em&gt;ServerGarbageCollection false&lt;/em&gt; com &lt;em&gt;ConcurrentGarbageCollection true&lt;/em&gt; aumenta o tempo de processamento.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;
&lt;span class="py"&gt;BenchmarkDotNet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;v0.12.1, OS=ubuntu 20.04&lt;/span&gt;
&lt;span class="err"&gt;Intel&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;i7-7500U&lt;/span&gt; &lt;span class="err"&gt;CPU&lt;/span&gt; &lt;span class="err"&gt;2.70GHz&lt;/span&gt; &lt;span class="err"&gt;(Kaby&lt;/span&gt; &lt;span class="err"&gt;Lake),&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;CPU,&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;logical&lt;/span&gt; &lt;span class="err"&gt;cores&lt;/span&gt; &lt;span class="err"&gt;and&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;physical&lt;/span&gt; &lt;span class="err"&gt;core&lt;/span&gt;
&lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="py"&gt;SDK&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3.1.405&lt;/span&gt;
  &lt;span class="nn"&gt;[Host]&lt;/span&gt;                &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;Server&lt;/span&gt;                &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;ServerConcurrent&lt;/span&gt;      &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;Workstation&lt;/span&gt;           &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;WorkstationConcurrent&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;

&lt;span class="py"&gt;IterationCount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;15  LaunchCount=2  WarmupCount=10  &lt;/span&gt;

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

&lt;/div&gt;


&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Concurrent&lt;/th&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Median&lt;/th&gt;
&lt;th&gt;Gen 0&lt;/th&gt;
&lt;th&gt;Gen 1&lt;/th&gt;
&lt;th&gt;Gen 2&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;428.7 ms&lt;/td&gt;
&lt;td&gt;72.57 ms&lt;/td&gt;
&lt;td&gt;108.62 ms&lt;/td&gt;
&lt;td&gt;428.8 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;389.94 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;483.2 ms&lt;/td&gt;
&lt;td&gt;54.60 ms&lt;/td&gt;
&lt;td&gt;81.72 ms&lt;/td&gt;
&lt;td&gt;516.0 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;146.13 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;458.3 ms&lt;/td&gt;
&lt;td&gt;63.28 ms&lt;/td&gt;
&lt;td&gt;94.72 ms&lt;/td&gt;
&lt;td&gt;514.9 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;146.64 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;ServerConcurrent&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;519.6 ms&lt;/td&gt;
&lt;td&gt;12.83 ms&lt;/td&gt;
&lt;td&gt;17.98 ms&lt;/td&gt;
&lt;td&gt;515.4 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;381.52 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;ServerConcurrent&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;354.8 ms&lt;/td&gt;
&lt;td&gt;50.80 ms&lt;/td&gt;
&lt;td&gt;72.85 ms&lt;/td&gt;
&lt;td&gt;327.6 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;145.77 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;ServerConcurrent&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;490.3 ms&lt;/td&gt;
&lt;td&gt;75.63 ms&lt;/td&gt;
&lt;td&gt;110.86 ms&lt;/td&gt;
&lt;td&gt;516.2 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;148.85 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;484.2 ms&lt;/td&gt;
&lt;td&gt;57.89 ms&lt;/td&gt;
&lt;td&gt;83.03 ms&lt;/td&gt;
&lt;td&gt;513.9 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;307.69 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;432.8 ms&lt;/td&gt;
&lt;td&gt;75.27 ms&lt;/td&gt;
&lt;td&gt;105.52 ms&lt;/td&gt;
&lt;td&gt;508.2 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;146.98 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;580.9 ms&lt;/td&gt;
&lt;td&gt;60.71 ms&lt;/td&gt;
&lt;td&gt;87.07 ms&lt;/td&gt;
&lt;td&gt;534.8 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;148.18 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;WorkstationConcurrent&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;544.1 ms&lt;/td&gt;
&lt;td&gt;61.84 ms&lt;/td&gt;
&lt;td&gt;90.64 ms&lt;/td&gt;
&lt;td&gt;530.3 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;307.95 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;WorkstationConcurrent&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;661.8 ms&lt;/td&gt;
&lt;td&gt;94.76 ms&lt;/td&gt;
&lt;td&gt;132.85 ms&lt;/td&gt;
&lt;td&gt;710.2 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;151.16 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;WorkstationConcurrent&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;565.5 ms&lt;/td&gt;
&lt;td&gt;129.98 ms&lt;/td&gt;
&lt;td&gt;182.21 ms&lt;/td&gt;
&lt;td&gt;541.9 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;143.86 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Exemplo
&lt;/h2&gt;

&lt;p&gt;No mês de janeiro uma API começou a ter muitos problemas de estouro de memória, lembrando que essa aplicação está utilizando o plano B1 e não está sozinha no &lt;em&gt;Service Plan&lt;/em&gt;. Olha como estava o consumo de memória na época:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--szWB6E-f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/to9ocawvnv4rnt6jow8i.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--szWB6E-f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/to9ocawvnv4rnt6jow8i.PNG" alt="Consumo de memória na epoca"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos notar que essa api consumia uns 280mb em média, mas teve um pico de 800mb. Depois de aplica essa otimização observe como está o consumo de memória um mês depois:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TyRKFQ0n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/puxuxvjyybkp0y7rn3qh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TyRKFQ0n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/puxuxvjyybkp0y7rn3qh.PNG" alt="Consumo de memória um mês depois"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O consumo de memória não passa de 200mb. Já está rodando a alguns dias e não voltamos a ter problemas com essa API.&lt;/p&gt;

&lt;p&gt;O que foi possível observar é uma considerável redução do consumo de memoria e uma aplicação mais estável no Service Plan B1.&lt;/p&gt;
&lt;h2&gt;
  
  
  Estudos futuros
&lt;/h2&gt;

&lt;p&gt;Existem outras opções que posso alterar, mas como é um assunto bem complicado fica para uma publicação futura. Nem comentei quando estamos trabalhando em um ambiente de container (ex: docker), podemos definir um limite para a heap sem precisar altera o tipo de GC. Caso queriam saber mais, curte esse material:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/running-with-server-gc-in-a-small-container-scenario-part-0/"&gt;Running with Server GC in a Small Container Scenario Part 0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/running-with-server-gc-in-a-small-container-scenario-part-1-hard-limit-for-the-gc-heap/"&gt;Running with Server GC in a Small Container Scenario Part 1 – Hard Limit for the GC Heap
&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Vou deixar uma lista de conteúdo para você conhecer mais sobre o assunto.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/workstation-gc-for-server-applications/"&gt;Workstation GC for server applications?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/garbage-collection-at-food-courts/"&gt;Garbage Collection at Food Courts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/pt-br/dotnet/core/run-time-config/garbage-collector"&gt;Run-time configuration options for garbage collection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/premier-developer/understanding-different-gc-modes-with-concurrency-visualizer/"&gt;Understanding different GC modes with Concurrency Visualizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/middle-ground-between-server-and-workstation-gc/"&gt;Middle Ground between Server and Workstation GC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/workstation-server-gc"&gt;Workstation and server garbage collection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#ephemeral-generations-and-segments"&gt;Fundamentals of garbage collection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="ltag__user ltag__user__id__426430"&gt;
  
    .ltag__user__id__426430 .follow-action-button {
      background-color: #008000 !important;
      color: #dce9f3 !important;
      border-color: #008000 !important;
    }
  
    &lt;a href="/juscelior" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4xok3liq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--nZjGgy2R--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/426430/ab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt="juscelior image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/juscelior"&gt;Pode me chamar de Juscélio Reis&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/juscelior"&gt; Professional in constant learning, software developer with almost 10 years of career, researcher on distributed systems and information security. Strong experience in software development with C #&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>azure</category>
      <category>csharp</category>
      <category>devz</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>HttpClient: melhoria de performance ao otimizar o uso de memória</title>
      <dc:creator>Pode me chamar de Juscélio Reis</dc:creator>
      <pubDate>Thu, 04 Feb 2021 21:37:42 +0000</pubDate>
      <link>https://forem.com/devzwiz/httpclient-melhoria-de-performance-ao-otimizar-o-uso-de-memoria-4nj3</link>
      <guid>https://forem.com/devzwiz/httpclient-melhoria-de-performance-ao-otimizar-o-uso-de-memoria-4nj3</guid>
      <description>&lt;p&gt;Neste último mês fiquei investigando incidentes relacionados a alto consumo de memória por parte das nossas aplicações. Consegui encontrar alguns problemas e quero compartilhar com vocês, vamos começar com a utilização do HttpClient, esse cara pode ser um vilão se não for bem utilizado. As APIs da Wiz têm uma característica de chamar outras APIs e me atrevo a dizer que é mais consumo de API do que utilização de banco de dados. Nesse artigo quero explicar como você pode otimizar o desempenho do HttpClient ao lidar com dados como cargas úteis JSON no HttpResponseMessage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teoria
&lt;/h2&gt;

&lt;p&gt;O que eu não sabia era que por padrão, na maioria dos casos, ao usar HttpClient e seus metodos (GetAsync, PostAsync e SendAsync), todo o corpo da resposta é lido em um buffer de memória antes que o método seja concluído. Nesse ponto, a conexão TCP, usada para a solicitação fica inativa e estará disponível para reutilização para outra solicitação, um ponto aqui é que estou falando do &lt;strong&gt;dotnet core 3.1&lt;/strong&gt;, se for falar do dotnet 5, existem opções melhores como é o caso da utilização do protocolo http2, aí a história é outra.&lt;/p&gt;

&lt;p&gt;Na maioria dos casos esse comportamento é aceitável, já que evita o uso da conexão tcp pelo período mínimo de tempo necessário. Mas... em casos que não temos memória sobressalente, aí entramos no caminho infeliz da história pois essa abordagem padrão introduz alguma sobrecarga de memória. Já que a resposta da API, vou generalizar aqui, o JSON é armazenado em buffer usando um MemoryStream, podemos acessar esse buffer pela classe HttpResponseMessage. Dependendo do tamanho da carga de resposta, isso pode significar que armazenamos em buffer uma grande quantidade de dados na memória.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solução
&lt;/h2&gt;

&lt;p&gt;O que eu não sabia era que existe uma sobrecarga desses métodos esperando um &lt;em&gt;enum&lt;/em&gt; HttpCompletionOption, esse &lt;em&gt;enum&lt;/em&gt; possui 2 valores o padrão é o ResponseContentRead, esse aí informa para o HttpClient que é para ler o corpo do JSON e colocar em memória mesmo que a nossa aplicação não vai usar esse objeto, sim isso é possível. O segundo valor é o que iremos começar a utilizar aqui na Wiz chamado ResponseHeadersRead, esse cara indica para o HttpClient quando os cabeçalhos de resposta forem totalmente lidos. O corpo da resposta pode não ser totalmente recebido neste momento.&lt;/p&gt;

&lt;p&gt;O principal benefício é o desempenho. Ao usar esta opção, evitamos o buffer MemoryStream intermediário, em vez de obter o conteúdo diretamente do fluxo exposto no Socket. Isso evita alocações desnecessárias, o que é uma meta em situações altamente otimizadas.&lt;/p&gt;

&lt;p&gt;Aqui vai um exemplo, quero serializar uma lista de livros apenas quando receber um status code 200. Se eu receber um 500 vou lançar uma exception e não preciso do conteúdo da API que estou consumindo.&lt;/p&gt;

&lt;p&gt;A forma de utilizar esse enum é bem simples, olha como fica:&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;_httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://openlibrary.org/search.json?q=tdd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpCompletionOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseHeadersRead&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;O normal é analisar o conteúdo de alguma forma. Vou mostrar um código de como podemos escrever nossa chamada para isso.&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;var&lt;/span&gt; &lt;span class="n"&gt;response&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;_httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://openlibrary.org/search.json?q=tdd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpCompletionOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseHeadersRead&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kt"&gt;object&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;stream&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStreamAsync&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;data&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;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// do something with the data or return it&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Usamos o EnsureSuccessStatusCode para garantir que o status code recebido é um 2xx. Em caso afirmativo, verificamos se há conteúdo disponível na resposta. Agora podemos acessar o fluxo do conteúdo de resposta usando ReadAsStreamAsync.&lt;/p&gt;

&lt;p&gt;O problema dessa abordagem é que assumimos mais responsabilidade em relação aos recursos do sistema, uma vez que a conexão com o servidor remoto fica presa até decidirmos que terminaremos com o conteúdo. A maneira como sinalizamos isso é descartando o HttpResponseMessage, que então libera a conexão para ser usada para outras solicitações. Por isso não esquecer do &lt;em&gt;using&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;var&lt;/span&gt; &lt;span class="n"&gt;response&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;_httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAsync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Outra forma de garantir isso é usar o try/finaly, veja um exemplo:&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;response&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;_httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://openlibrary.org/search.json?q=tdd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpCompletionOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseHeadersRead&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;Search&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kt"&gt;object&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;stream&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStreamAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;finally&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// intensive and slow processing of books list. We don't want this to delay releasing the connection.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Estudo de caso
&lt;/h2&gt;

&lt;p&gt;Fiz um programa de teste para ter um benchmark da performance do que citei nesse artigo. Essa analise é feita tanto no Windows como no Linux, usando o dotnet core 3.1. Vocês podem &lt;a href="https://github.com/juscelior/benchmarkhttp" rel="noopener noreferrer"&gt;acessar aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Observe a coluna Allocated, usando um sistema Windows com o método WithHttpCompletionOption chegamos a uma performance de 26,87% em comparação com WithoutHttpCompletionOption que representa 73,13% do consumo de memória.&lt;/p&gt;

&lt;p&gt;Agora usando um sistema Linux com o método WithHttpCompletionOption chegamos a uma performance de 28,62% em comparação com o método WithoutHttpCompletionOption que representa 71,38% do consumo de memória.&lt;/p&gt;
&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;
&lt;span class="py"&gt;BenchmarkDotNet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;v0.12.1, OS=Windows 10.0.19042&lt;/span&gt;
&lt;span class="err"&gt;Intel&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;i7-7500U&lt;/span&gt; &lt;span class="err"&gt;CPU&lt;/span&gt; &lt;span class="err"&gt;2.70GHz&lt;/span&gt; &lt;span class="err"&gt;(Kaby&lt;/span&gt; &lt;span class="err"&gt;Lake),&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;CPU,&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt; &lt;span class="err"&gt;logical&lt;/span&gt; &lt;span class="err"&gt;and&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;physical&lt;/span&gt; &lt;span class="err"&gt;cores&lt;/span&gt;
&lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="py"&gt;SDK&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3.1.404&lt;/span&gt;
  &lt;span class="nn"&gt;[Host]&lt;/span&gt;           &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.10&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51601,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51901),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;Server&lt;/span&gt;           &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.10&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51601,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51901),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;ServerForce&lt;/span&gt;      &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.10&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51601,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51901),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;Workstation&lt;/span&gt;      &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.10&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51601,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51901),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;WorkstationForce&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.10&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51601,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.51901),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;

&lt;span class="py"&gt;IterationCount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;15  LaunchCount=2  WarmupCount=10  &lt;/span&gt;

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

&lt;/div&gt;


&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Force&lt;/th&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Median&lt;/th&gt;
&lt;th&gt;Gen 0&lt;/th&gt;
&lt;th&gt;Gen 1&lt;/th&gt;
&lt;th&gt;Gen 2&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;477.6 ms&lt;/td&gt;
&lt;td&gt;65.79 ms&lt;/td&gt;
&lt;td&gt;96.43 ms&lt;/td&gt;
&lt;td&gt;515.4 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;404.48 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;673.4 ms&lt;/td&gt;
&lt;td&gt;73.56 ms&lt;/td&gt;
&lt;td&gt;103.12 ms&lt;/td&gt;
&lt;td&gt;723.6 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;162.16 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;703.2 ms&lt;/td&gt;
&lt;td&gt;149.15 ms&lt;/td&gt;
&lt;td&gt;213.91 ms&lt;/td&gt;
&lt;td&gt;662.3 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;162.66 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;ServerForce&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;414.7 ms&lt;/td&gt;
&lt;td&gt;65.04 ms&lt;/td&gt;
&lt;td&gt;93.27 ms&lt;/td&gt;
&lt;td&gt;363.7 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;394.98 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;ServerForce&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;642.0 ms&lt;/td&gt;
&lt;td&gt;81.61 ms&lt;/td&gt;
&lt;td&gt;106.12 ms&lt;/td&gt;
&lt;td&gt;642.8 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;163.63 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;ServerForce&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;707.8 ms&lt;/td&gt;
&lt;td&gt;97.39 ms&lt;/td&gt;
&lt;td&gt;139.68 ms&lt;/td&gt;
&lt;td&gt;727.4 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;162.81 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;659.7 ms&lt;/td&gt;
&lt;td&gt;96.77 ms&lt;/td&gt;
&lt;td&gt;132.46 ms&lt;/td&gt;
&lt;td&gt;643.2 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;394.62 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;530.2 ms&lt;/td&gt;
&lt;td&gt;9.43 ms&lt;/td&gt;
&lt;td&gt;12.59 ms&lt;/td&gt;
&lt;td&gt;528.1 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;162.35 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;439.2 ms&lt;/td&gt;
&lt;td&gt;65.54 ms&lt;/td&gt;
&lt;td&gt;98.10 ms&lt;/td&gt;
&lt;td&gt;452.9 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;161.59 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;WorkstationForce&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;499.3 ms&lt;/td&gt;
&lt;td&gt;52.65 ms&lt;/td&gt;
&lt;td&gt;77.17 ms&lt;/td&gt;
&lt;td&gt;517.6 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;394.89 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;WorkstationForce&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;626.4 ms&lt;/td&gt;
&lt;td&gt;69.05 ms&lt;/td&gt;
&lt;td&gt;94.52 ms&lt;/td&gt;
&lt;td&gt;600.1 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;162.98 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;WorkstationForce&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;508.5 ms&lt;/td&gt;
&lt;td&gt;57.64 ms&lt;/td&gt;
&lt;td&gt;82.67 ms&lt;/td&gt;
&lt;td&gt;524.8 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;162.39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;
&lt;span class="py"&gt;BenchmarkDotNet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;v0.12.1, OS=ubuntu 20.04&lt;/span&gt;
&lt;span class="err"&gt;Intel&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;i7-7500U&lt;/span&gt; &lt;span class="err"&gt;CPU&lt;/span&gt; &lt;span class="err"&gt;2.70GHz&lt;/span&gt; &lt;span class="err"&gt;(Kaby&lt;/span&gt; &lt;span class="err"&gt;Lake),&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;CPU,&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt; &lt;span class="err"&gt;logical&lt;/span&gt; &lt;span class="err"&gt;cores&lt;/span&gt; &lt;span class="err"&gt;and&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;physical&lt;/span&gt; &lt;span class="err"&gt;core&lt;/span&gt;
&lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="py"&gt;SDK&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3.1.405&lt;/span&gt;
  &lt;span class="nn"&gt;[Host]&lt;/span&gt;           &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;Server&lt;/span&gt;           &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;ServerForce&lt;/span&gt;      &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;Workstation&lt;/span&gt;      &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;
  &lt;span class="err"&gt;WorkstationForce&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;.NET&lt;/span&gt; &lt;span class="err"&gt;Core&lt;/span&gt; &lt;span class="err"&gt;3.1.11&lt;/span&gt; &lt;span class="err"&gt;(CoreCLR&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56602,&lt;/span&gt; &lt;span class="err"&gt;CoreFX&lt;/span&gt; &lt;span class="err"&gt;4.700.20.56604),&lt;/span&gt; &lt;span class="err"&gt;X64&lt;/span&gt; &lt;span class="err"&gt;RyuJIT&lt;/span&gt;

&lt;span class="py"&gt;IterationCount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;15  LaunchCount=2  WarmupCount=10  &lt;/span&gt;

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

&lt;/div&gt;


&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Force&lt;/th&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Median&lt;/th&gt;
&lt;th&gt;Gen 0&lt;/th&gt;
&lt;th&gt;Gen 1&lt;/th&gt;
&lt;th&gt;Gen 2&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;426.4 ms&lt;/td&gt;
&lt;td&gt;73.53 ms&lt;/td&gt;
&lt;td&gt;100.64 ms&lt;/td&gt;
&lt;td&gt;409.1 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;389120 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;360.1 ms&lt;/td&gt;
&lt;td&gt;53.91 ms&lt;/td&gt;
&lt;td&gt;77.31 ms&lt;/td&gt;
&lt;td&gt;331.1 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;152472 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;328.8 ms&lt;/td&gt;
&lt;td&gt;12.37 ms&lt;/td&gt;
&lt;td&gt;17.74 ms&lt;/td&gt;
&lt;td&gt;323.7 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;149624 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;ServerForce&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;421.0 ms&lt;/td&gt;
&lt;td&gt;71.88 ms&lt;/td&gt;
&lt;td&gt;103.09 ms&lt;/td&gt;
&lt;td&gt;426.8 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;406960 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;ServerForce&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;515.3 ms&lt;/td&gt;
&lt;td&gt;71.17 ms&lt;/td&gt;
&lt;td&gt;104.32 ms&lt;/td&gt;
&lt;td&gt;520.8 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;149936 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;ServerForce&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;525.4 ms&lt;/td&gt;
&lt;td&gt;142.11 ms&lt;/td&gt;
&lt;td&gt;203.81 ms&lt;/td&gt;
&lt;td&gt;515.6 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;150136 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;523.6 ms&lt;/td&gt;
&lt;td&gt;94.41 ms&lt;/td&gt;
&lt;td&gt;138.38 ms&lt;/td&gt;
&lt;td&gt;515.3 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;149520 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;Workstation&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;582.9 ms&lt;/td&gt;
&lt;td&gt;288.63 ms&lt;/td&gt;
&lt;td&gt;404.62 ms&lt;/td&gt;
&lt;td&gt;354.0 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;150072 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithoutHttpCompletionOption&lt;/td&gt;
&lt;td&gt;WorkstationForce&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;523.4 ms&lt;/td&gt;
&lt;td&gt;44.34 ms&lt;/td&gt;
&lt;td&gt;62.16 ms&lt;/td&gt;
&lt;td&gt;527.0 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;389112 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithHttpCompletionOption&lt;/td&gt;
&lt;td&gt;WorkstationForce&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;523.0 ms&lt;/td&gt;
&lt;td&gt;11.63 ms&lt;/td&gt;
&lt;td&gt;16.68 ms&lt;/td&gt;
&lt;td&gt;518.3 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;150680 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WithGetStreamAsync&lt;/td&gt;
&lt;td&gt;WorkstationForce&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;427.7 ms&lt;/td&gt;
&lt;td&gt;78.15 ms&lt;/td&gt;
&lt;td&gt;104.33 ms&lt;/td&gt;
&lt;td&gt;497.9 ms&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;151472 B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;div class="ltag__user ltag__user__id__426430"&gt;
    &lt;a href="/juscelior" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F426430%2Fab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt="juscelior image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/juscelior"&gt;Pode me chamar de Juscélio Reis&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/juscelior"&gt; Professional in constant learning, software developer with almost 10 years of career, researcher on distributed systems and information security. Strong experience in software development with C #&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>wiz</category>
      <category>devz</category>
    </item>
    <item>
      <title>Teste de integração com SqlServer e Azure Devops</title>
      <dc:creator>Tiago Brito</dc:creator>
      <pubDate>Thu, 17 Dec 2020 12:54:29 +0000</pubDate>
      <link>https://forem.com/devzwiz/teste-de-integracao-com-sqlserver-e-azure-devops-2cl</link>
      <guid>https://forem.com/devzwiz/teste-de-integracao-com-sqlserver-e-azure-devops-2cl</guid>
      <description>&lt;p&gt;Há poucos dias atrás fiz uma implementação para integrar meus testes com o Sql Server. &lt;/p&gt;

&lt;h2&gt;
  
  
  Motivação
&lt;/h2&gt;

&lt;p&gt;O que me levou a escrever esse tipo de teste foi: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quero escrever um testes que seja o mais aderente ao ambiente de produção - ou seja, se vai rodar em Sql Server – tenho que escrever um testes que rode em Sql Server &lt;/li&gt;
&lt;li&gt;Quero testar consultas mais complexas; &lt;/li&gt;
&lt;li&gt;Quero testar cada método da minha classe de repositório, com cenário próprio, sem precisar rodar o sistema inteiro para fazer realizar este teste; &lt;/li&gt;
&lt;li&gt;Possibilidade de testes transacionais &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Para rodar os testes segui os seguintes passos:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Montei um Sql Server em um container; &lt;/li&gt;
&lt;li&gt;Escrevi um código para criação da estrutura de banco, cenário e execução dos teste de repositórios; &lt;/li&gt;
&lt;li&gt;Escrevi os testes propriamente ditos; &lt;/li&gt;
&lt;li&gt;Configurei o pipeline do Azure para subir uma instância do Sql Server em tempo de build antes de rodar os testes integrados com repositórios. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exemplo do método de repositório que quero testar
&lt;/h3&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByEmailAsync&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;email&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;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@" 
SELECT  
      u.Id, u.FirstName, u.LastName, u.PersonalIdentificationNumber, 
      u.Email, u.ProfileCode, u.DateCreated 
FROM  
          [dbo].[User] u                 
WHERE  
    u.Email = @Email 
    AND u.TenantId = @TenantId"&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;await&lt;/span&gt; &lt;span class="n"&gt;_dapperContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DapperConnection&lt;/span&gt; 
                   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt; 
                        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TenantId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SqlServer no meu ambiente de desenvolvimento
&lt;/h2&gt;

&lt;p&gt;Criei um container (docker) para instância do Sql Server. Para subir o Sql Server disponibilizo meu docker-compose que utilizei para inicialização do container; &lt;/p&gt;

&lt;p&gt;Meu sistema operacional é o Windows então, utilizei o &lt;em&gt;docker&lt;/em&gt; for windows disponível &lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Salve um arquivo em alguma pasta no seu computador com esse conteúdo. No meu ambiente, salvei aqui [C:_devz\dockers\sqlserver] &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;docker-compose.yml&lt;/strong&gt;&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt; 

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcr.microsoft.com/mssql/server:2017-latest-ubuntu&lt;/span&gt; 
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="na"&gt;SA_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Q1w2e3r4!"&lt;/span&gt; 
            &lt;span class="na"&gt;ACCEPT_EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Y&lt;/span&gt; 
            &lt;span class="na"&gt;MSSQL_PID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Express&lt;/span&gt; 
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1433:1433"&lt;/span&gt; 
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mssql-volume:/var/lib/mssql&lt;/span&gt; 
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mssql_docknet&lt;/span&gt;            
&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;mssql_docknet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;                
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;mssql-volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para executar o container, execute no prompt como abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; cd C:\_devz\Dockers\sqlserver [Esse é o local onde está o docker-compose.yml] 

&amp;gt; docker-compose up –d 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Código para estrutura e conexão com banco de dados
&lt;/h2&gt;

&lt;p&gt;Para que meu teste funcionasse precisei de uma instância do Sql Server funcionando - instância que configurei acima; &lt;/p&gt;

&lt;p&gt;Para ter cenários e testes independentes, antes que os testes fossem executados: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criei uma classe de contexto compartilhado que o xunit disponibiliza; &lt;/li&gt;
&lt;li&gt;Esse contexto cria o banco de dados; &lt;/li&gt;
&lt;li&gt;Esse contexto cria as tabelas configuradas no Entity;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;CollectionDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DatabaseTestCollection"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseCollection&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ICollectionFixture&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DatabaseFixture&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com essa classe eu defini um contexto global para todos os meus testes. Essa classe é assim mesmo - não tem código nenhum em seu corpo. &lt;/p&gt;

&lt;p&gt;Na classe &lt;strong&gt;DatabaseFixture&lt;/strong&gt; tenho as informações do banco de dados e a inicialização do banco; &lt;/p&gt;

&lt;p&gt;Nesta classe configurei as informações do Entity e do Dapper; &lt;br&gt;
Com essas informações, meu banco de dados de teste é criado;&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="n"&gt;DapperContext&lt;/span&gt; &lt;span class="n"&gt;_dapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DatabaseFixture&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="c1"&gt;////minha string de conexão que se conecta com o container montado&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"Server=localhost;Database=gamificacao_test;User ID=sa;Password=Q1w2e3r4!;Trusted_Connection=False;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;////Adicionei algumas configurações para rastrear problemas de banco ao rodar meus testes&lt;/span&gt;
    &lt;span class="n"&gt;ContextOptions&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;DbContextOptionsBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EntityContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; 
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableSensitiveDataLogging&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseLoggerFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDebug&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="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;////Como se trata de um cenário de testes algumas coisas coloquei em memória por não ser relevante para o testes&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;myConfiguration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&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="s"&gt;"ConnectionStrings:GamificacaoDB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;};&lt;/span&gt; 

    &lt;span class="n"&gt;_configuration&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;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddInMemoryCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myConfiguration&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;IdentityServiceMock&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;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IIdentityService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; 
    &lt;span class="n"&gt;IdentityServiceMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTenantId&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wx1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="n"&gt;Context&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;EntityContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContextOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IdentityServiceMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="n"&gt;_dapper&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;DapperContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="c1"&gt;//// Cria o meu banco de testes&lt;/span&gt;
    &lt;span class="nf"&gt;InitializeDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="c1"&gt;////Repositorios da minha API que pretendo testar&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionRepository&lt;/span&gt; &lt;span class="n"&gt;ActionRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ActionRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_dapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IdentityServiceMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_dapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IdentityServiceMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;InitializeDatabase&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="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&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;EntityContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContextOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IdentityServiceMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
            &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureDeleted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
                &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnsureCreated&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
            &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O repositório que pretendo testar
&lt;/h2&gt;

&lt;p&gt;Estou testando o repositório de usuários (&lt;em&gt;UserRepository&lt;/em&gt;). O método em questão está utilizando &lt;em&gt;Dapper&lt;/em&gt; e minha consulta é muito simples.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByEmailAsync&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;email&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;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@" 
SELECT  
      u.Id, u.FirstName, u.LastName, u.PersonalIdentificationNumber, 
      u.Email, u.ProfileCode, u.DateCreated 
FROM  
          [dbo].[User] u                 
WHERE  
    u.Email = @Email 
    AND u.TenantId = @TenantId"&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;await&lt;/span&gt; &lt;span class="n"&gt;_dapperContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DapperConnection&lt;/span&gt; 
                   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt; 
                        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TenantId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O Teste
&lt;/h2&gt;

&lt;p&gt;Quando a instância do SqlServer iniciou não tenho nenhuma informação nas tabelas para executar os testes. Então, preciso criar esses dados. Para isso, utilizei as mesmas classes de criação de objetos que já temos em nossa estrutura. Veja no teste abaixo: Criei 1 Usuário. &lt;/p&gt;

&lt;p&gt;Para o contexto dos testes criei um método estendido para as entidades. Nesse método consigo inserir no banco de dados o que está na entidade. Isso facilita inclusão de dados nas tabelas sem a necessidade de chamar o repositório para inserir.&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EntityExtensions&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;T&lt;/span&gt; &lt;span class="n"&gt;Persist&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt; 
           &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
           &lt;span class="n"&gt;EntityContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; 
    &lt;span class="err"&gt;{&lt;/span&gt; 
        &lt;span class="nc"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChanges&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;entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então, na linha onde temos &lt;strong&gt;user.Persist(_databaseFixture.Context)&lt;/strong&gt; a tabela &lt;em&gt;User&lt;/em&gt; será persistida. &lt;/p&gt;

&lt;p&gt;O mesmo aconteceria com outros objetos onde chamando o .Persist().&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="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&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;GetByMail_TestAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;//Cenario &lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tiago&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;Domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"tiagobrito@wizsolucoes.com.br"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Tiago"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Brito"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;ProfileCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;PersonalIdentificationNumber&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"15476338731"&lt;/span&gt; 
    &lt;span class="p"&gt;};&lt;/span&gt; 

    &lt;span class="n"&gt;tiago&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_databaseFixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="c1"&gt;//Execução &lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userToCompare&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;_databaseFixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserRepository&lt;/span&gt;                                 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetByEmailAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tiagobrito@wizsolucoes.com.br"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

     &lt;span class="c1"&gt;///Validação &lt;/span&gt;
    &lt;span class="n"&gt;userToCompare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ElementAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tiago"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="n"&gt;userToCompare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ElementAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Brito"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
 &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userToCompare&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;_databaseFixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserRepository&lt;/span&gt;                           &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetByEmailAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tiagobrito@wizsolucoes.com.br"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

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

&lt;/div&gt;



&lt;p&gt;Na linha acima temos a execução do repositório. Nesta etapa, todos os meus dados já estão persistidos e, se alimentei as tabela corretamente e minha classe de repositório estiver com a consulta correta, os dados virão. Estamos testando apenas essa unidade. Fica bem simples e não preciso rodar o sistema inteiro. &lt;/p&gt;

&lt;p&gt;Para validar os retornos utilizamos o que já conhecemos  &lt;/p&gt;

&lt;p&gt;Eu utilizo uma biblioteca para &lt;em&gt;assert&lt;/em&gt; fluente – considero que a leitura do teste fica bem legal. pode ser encontrada &lt;a href="https://fluentassertions.com/introduction" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;userToCompare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ElementAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tiago"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="n"&gt;userToCompare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ElementAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Brito"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuração do pipeline para testes de integração com Sql Sever no Azure
&lt;/h2&gt;

&lt;p&gt;Como mencionado no primeiro tópico, utilizo um container para subir uma instancia do Sql Server Express e realizar os testes. No Azure Devops fiz o mesmo: no arquivo &lt;strong&gt;azure-pipelines.yml&lt;/strong&gt; do projeto descrevi o recurso que precisava nas extensões, segundo o novo modelo de pipeline, identifiquei o serviço que vou utilizar. No caso, o Sql Server.&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="c1"&gt;# ASP.NET Core&lt;/span&gt;
&lt;span class="c1"&gt;# Build a Web project that uses ASP.NET Core.&lt;/span&gt;
&lt;span class="c1"&gt;# Add steps that analyze code, save build artifacts, deploy, and more:&lt;/span&gt;
&lt;span class="c1"&gt;# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core&lt;/span&gt;
&lt;span class="c1"&gt;# YAML reference:&lt;/span&gt;
&lt;span class="c1"&gt;# https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema&lt;/span&gt;

&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;azResourceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;meu-projeto'&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnettemplate&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git&lt;/span&gt;  
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meurepositorio/modelos&lt;/span&gt;
      &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;refs/tags/v1.1&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcr.microsoft.com/mssql/server:2017-latest-ubuntu&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1433:1433&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Q1w2e3r4!' -e 'MSSQL_PID=Express'&lt;/span&gt;

&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt;

&lt;span class="na"&gt;schedules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Noturno&lt;/span&gt;
    &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;batch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;README.md&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Wiz Hosted Ubuntu &lt;/span&gt;&lt;span class="m"&gt;1604&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;continueOnError&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;localhostsqlserver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql&lt;/span&gt;
      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="c1"&gt;#Essas linhas com powershell são apenas para testes. podem ser removidas&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PowerShell@2&lt;/span&gt;
          &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;delay&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;10'&lt;/span&gt;
          &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;targetType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inline'&lt;/span&gt;
            &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;# Write your PowerShell commands here.&lt;/span&gt;
              &lt;span class="s"&gt;start-sleep -s 10&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CmdLine@2&lt;/span&gt;
          &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sqlcmd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-S&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;master&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sa&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-P&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Q1w2e3r4!&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-Q&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"SELECT&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;@@version;"'&lt;/span&gt;
         &lt;span class="c1"&gt;#Esse template compila aplicações .net&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnetcore.yml@dotnettemplate&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Uat&lt;/span&gt;
  &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;and(succeeded(), or(contains(variables['Build.SourceBranch'], 'master'), contains(variables['Build.SourceBranch'], 'releases')))&lt;/span&gt;
  &lt;span class="na"&gt;dependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Build&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
      &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runOnce&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                              
            &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AzureRmWebAppDeployment@4&lt;/span&gt;
              &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish&lt;/span&gt; 
              &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;ConnectionType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AzureRM'&lt;/span&gt;
                &lt;span class="na"&gt;azureSubscription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;xxx'&lt;/span&gt;
                &lt;span class="na"&gt;appType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;webApp'&lt;/span&gt;
                &lt;span class="na"&gt;WebAppName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(azResourceName)-hml-api'&lt;/span&gt;
                &lt;span class="na"&gt;packageForLinux&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(Pipeline.Workspace)/drop/**/*.zip'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O YML abaixo é bem simplificado e é o que utilizamos na Wiz. Isso porque nossa equipe de governança trabalhou algum tempo para torná-lo simples assim.&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;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coretemplate&lt;/span&gt; 
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git&lt;/span&gt; 
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meu/repositorio&lt;/span&gt; 

  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql&lt;/span&gt; 
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcr.microsoft.com/mssql/server:2017-latest-ubuntu&lt;/span&gt; 
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;ACCEPT_EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Y&lt;/span&gt; 
      &lt;span class="na"&gt;SA_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Q1w2e3r4!&lt;/span&gt; 
      &lt;span class="na"&gt;MSSQL_PID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Express&lt;/span&gt; 
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1433:1433&lt;/span&gt; 
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--name mssql&lt;/span&gt; 

&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest'&lt;/span&gt; 

&lt;span class="na"&gt;schedules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; 
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Noturno&lt;/span&gt; 
    &lt;span class="na"&gt;always&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt; 
&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;batch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;README.md&lt;/span&gt; 

&lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main.yml@coretemplate&lt;/span&gt; 
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;technology&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dotnetcore'&lt;/span&gt; 
    &lt;span class="na"&gt;dotnetcoreAppType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;apiApp'&lt;/span&gt; 
    &lt;span class="na"&gt;azResourceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gamificacao'&lt;/span&gt; 
    &lt;span class="na"&gt;azSubscriptionUAT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;xxx'&lt;/span&gt; 
    &lt;span class="na"&gt;azSubscriptionPRD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;xxx'&lt;/span&gt; 
    &lt;span class="na"&gt;dotnetcoreDotNetVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.x'&lt;/span&gt; 
    &lt;span class="na"&gt;dotnetcoreBuildProject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/*[API].csproj'&lt;/span&gt; 
    &lt;span class="na"&gt;dotnetcoreBuildConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt; 
    &lt;span class="na"&gt;dotnetcoreTestProject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/*[Tt]ests/*.csproj'&lt;/span&gt; 
    &lt;span class="na"&gt;dotnetcoreNugetFeed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;09b2821a-2950-4eff-a722-dbc8adf4da55&lt;/span&gt; 
    &lt;span class="na"&gt;buildServices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;mssql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql&lt;/span&gt; 
    &lt;span class="na"&gt;releaseServices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;mssql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No Azure podemos visualizar os resultados
&lt;/h2&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%2Fi%2F0ac21x7kk4a399r9af4v.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%2Fi%2F0ac21x7kk4a399r9af4v.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>devops</category>
      <category>azure</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>[Série] Governança de API: Contrato da API</title>
      <dc:creator>Pode me chamar de Juscélio Reis</dc:creator>
      <pubDate>Wed, 05 Aug 2020 19:35:57 +0000</pubDate>
      <link>https://forem.com/devzwiz/serie-governanca-de-api-contrato-da-api-2dd0</link>
      <guid>https://forem.com/devzwiz/serie-governanca-de-api-contrato-da-api-2dd0</guid>
      <description>&lt;h3&gt;
  
  
  Recapitulando:
&lt;/h3&gt;

&lt;p&gt;A área de governança precisa cruzar o anseio e desejos dos outros setores da empresa, com o objetivo de construir uma ponte entre o momento atual da empresa com o que pode acabar sendo uma futura estratégia de governança de API. &lt;/p&gt;

&lt;p&gt;É clichê, mas resumindo fica assim: a área de governança busca alinhar a estratégia com a execução.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;😒: Todo novo framework da moda tem essa frase. Como é possível esse alinhamento com a governança?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O monitoramento do desempenho &lt;strong&gt;passado&lt;/strong&gt; é útil na avaliação de opções no momento &lt;strong&gt;presente&lt;/strong&gt;, para determinar metas, políticas e ações &lt;strong&gt;futuras&lt;/strong&gt; (direção). 😎&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Aqueles que não conhecem a história estão fadados a repeti-la.&lt;br&gt;
-- Edmund Burke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como vai conseguir monitorar o passado se não sabe o que monitorar? No catalogo de API precisa existir no mínimo 4 informações, sendo elas o recurso, a estrutura, a capacidade e a sensibilidade. Logo ter um catalogo de API é o primeiro passo para o sucesso!&lt;/p&gt;

&lt;p&gt;Para recapitular pode ir direto na fonte:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/devzwiz" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F2646%2F4054ca95-31a5-4499-87e5-9d01726c16c2.png" alt="DEVz Wiz"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F426430%2Fab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/devzwiz/serie-governanca-de-api-ab2" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;[Série] Governança de API&lt;/h2&gt;
      &lt;h3&gt;Pode me chamar de Juscélio Reis for DEVz Wiz ・ Jul 21 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#governance&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#development&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 &lt;br&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/devzwiz" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F2646%2F4054ca95-31a5-4499-87e5-9d01726c16c2.png" alt="DEVz Wiz"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F426430%2Fab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/devzwiz/serie-governanca-de-api-centralizacao-2ebm" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt; [Série] Governança de API: Centralização&lt;/h2&gt;
      &lt;h3&gt;Pode me chamar de Juscélio Reis for DEVz Wiz ・ Jul 28 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#governance&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#development&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 
&lt;h3&gt;
  
  
  O contrato da API: o primeiro e mais importante passo
&lt;/h3&gt;

&lt;p&gt;Sem duvidas aqui é o ponto mais importante e mais complicado de ser feito, mas quando bem feito só temos ganhos. Para entender mais o motivo de começar com o contrato leia esse artigo:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/juscelior" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F426430%2Fab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt="juscelior"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/juscelior/por-que-devemos-comecar-nossas-apis-pelo-contrato-4i4h" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Por que devemos começar nossas APIs pelo contrato?&lt;/h2&gt;
      &lt;h3&gt;Pode me chamar de Juscélio Reis ・ Jul 13 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#apidevelopment&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#openapi&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#apigovernance&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 

&lt;p&gt;Em um programa de desenvolvimento de API a primeira etapa é justamente a construção de um contrato. Com um contrato bem feito conseguimos automatizar rotinas, melhorar a experiência do desenvolvedor, permitir a independência dos times, acelerar a entrega das APIs para o mercado, melhora o entendimento das suas APIs, facilitar a rotina de testes 👻, gerar SDKs tanto para o cliente quanto para o servidor (ação automatizada é claro), possibilidade de ativar e desativar suas APIs e como não podia deixar de ser, monitorar o passado!&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%2Fi%2F9jpv8ljlgvfz4ld4pmot.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9jpv8ljlgvfz4ld4pmot.jpg" alt="Ciclo de vida da API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;😒: o mundo real não é assim, ninguém para para criar contratos. O que o gestor quer é código em produção. Contrato, só se for contrato com um cliente pagante.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É uma visão bem comum, se você for direto para a criação de sua API, não haverá retorno ao design. É como construir uma casa e depois procurar um arquiteto para elaborar planos. Isso não faz nenhum sentido. 😎&lt;/p&gt;

&lt;p&gt;No entanto, as equipes de software frequentemente fazem escolhas semelhantes. Eles podem gerar uma especificação de API a partir do código, o que parece eficiente. Infelizmente, quando você criou uma API no código, perdeu muitas das vantagens da abordagem do design primeiro. Quando o design da sua API existe antes da implementação, você pode obter feedback antecipado, conectar sua API às ferramentas desde o início e colaborar entre departamentos e funções. 😎&lt;/p&gt;

&lt;p&gt;Colocar ordem no caos é uma tarefa árdua, ou exigir que desenvolvedores sigam um método que não seja o &lt;a href="https://gohorseprocess.com.br/extreme-go-horse-xgh/" rel="noopener noreferrer"&gt;eXtreme Go Horse (XGH)&lt;/a&gt;. Mas é necessário dar o primeiro passo. Assim também é implantar um programa de API, tenha em mente qual resultado deseja obter, e não foque no tamanho do percurso.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suba o primeiro degrau com fé. Não é necessário que você veja toda a escada. Apenas dê o primeiro passo.&lt;br&gt;
-- Martin Luther King&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Você sabe quem usará sua API? Mesmo para um projeto interno, é provável que você tenha vários consumidores. Uma especificação de API permite que você compartilhe detalhes sobre como a API funcionará. Você pode enviar o documento de especificação em si ou usar ferramentas para criar um protótipo de sua API ou documentação. Você pode gerar servidores simulados com base em suas especificações, conforme descrito em outra seção, e fazer com que seus consumidores façam chamadas ao vivo.&lt;/p&gt;

&lt;p&gt;Sua colaboração também pode ir além das equipes técnicas. Você pode obter ótimas informações sobre produtos, marketing, parcerias e &lt;strong&gt;muitas outras áreas da sua organização&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🙋‍♂️: Eu ouvi um amém irmãos?! 🙌🙌&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O software raramente é construído inteiramente por desenvolvedores. Existem partes interessadas em toda a organização. E embora muitos desenvolvedores possam ter muita atenção ao produto, eles nem sempre têm a visibilidade da imagem completa. Se sua organização possui um grupo de produtos, é nesse ponto que a voz do cliente é mais ouvida. &lt;strong&gt;Envolva qualquer pessoa que entenda como uma API será usada nas discussões ao criar a API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Quando você entender como o software será usado, poderá projetá-lo melhor. O maior erro no design da API é tomar decisões com base em como o sistema funciona, e não no que os consumidores precisam oferecer suporte. Para projetar casos de uso, você precisa conversar com os consumidores ou, pelo menos, incluir aqueles que os conhecem melhor.&lt;/p&gt;

&lt;p&gt;Uma sugestão de ferramenta que faz muito bem esse papel e para melhorar seu dia é gratuita &lt;a href="https://github.com/stoplightio/studio" rel="noopener noreferrer"&gt;Stoplight Studio&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/stoplightio" rel="noopener noreferrer"&gt;
        stoplightio
      &lt;/a&gt; / &lt;a href="https://github.com/stoplightio/studio" rel="noopener noreferrer"&gt;
        studio
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The modern editor for API Design and Technical Writing.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Stoplight Studio&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Studio is Stoplight's next generation application for API design, modeling, and technical writing. A primary goal of Studio is to enrich, not replace, your existing workflows. When running locally it works fully offline, with folders and files on your computer just like your favorite IDE. When running in the browser, the web-native Git support allows you to effortlessly work with your existing repositories safely and efficiently.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Documentation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;To learn more about Studio and the Stoplight platform, see our &lt;a href="https://meta.stoplight.io/" rel="nofollow noopener noreferrer"&gt;Platform Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Full Support for OpenAPI v2 and v3&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Studio comes with full support for the OpenAPI versions 2 and 3 specification formats for all functionality. That means full validation, mocking, and modeling support for both versions of the OpenAPI specification.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/stoplightio/studioassets/images/openapi_swagger_equal_heart.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fstoplightio%2Fstudioassets%2Fimages%2Fopenapi_swagger_equal_heart.png" alt="Studio loves Swagger + OpenAPI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Graphical API Design&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Form-based designing means you don't need to be an OpenAPI expert to get started. Studio has a "write" (code) mode with full OpenAPI autocomplete…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/stoplightio/studio" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
 

&lt;p&gt;Para gerar um mock desse contrato criado pelo &lt;a href="https://github.com/stoplightio/studio" rel="noopener noreferrer"&gt;Stoplight Studio&lt;/a&gt; é possível usar &lt;a href="https://github.com/stoplightio/prism" rel="noopener noreferrer"&gt;Prism&lt;/a&gt; na linha de comando e entregar esse mock para o dev front-end.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/stoplightio" rel="noopener noreferrer"&gt;
        stoplightio
      &lt;/a&gt; / &lt;a href="https://github.com/stoplightio/prism" rel="noopener noreferrer"&gt;
        prism
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Turn any OpenAPI2/3 and Postman Collection file into an API server with mocking, transformations and validations.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://stoplight.io/api-mocking?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=github_repo_prism" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fstoplightio%2Fprismexamples%2Freadme-header.svg" alt="Prism - API Mock Servers and Contract Testing"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://circleci.com/gh/stoplightio/prism" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b767c4d4c11f90bbb796b42d70d0e021526aff1ad78b88ab45a1ab1b5fe61053/68747470733a2f2f696d672e736869656c64732e696f2f636972636c6563692f6275696c642f6769746875622f73746f706c69676874696f2f707269736d2f6d6173746572" alt="CircleCI"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/@stoplight/prism-cli" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a9168759e6636aa1f0530a720fa61e9e03ef232c16ca7b7b5b93ef285488e294/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f64772f4073746f706c696768742f707269736d2d687474703f636f6c6f723d626c7565" alt="NPM Downloads"&gt;&lt;/a&gt;
&lt;a href="https://ecologi.com/stoplightinc" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e299fd92f5edda540adc59dfd62382f48d2bfb8798e7f7be5849ef8404e94ac8/68747470733a2f2f696d672e736869656c64732e696f2f65636f6c6f67692f74726565732f73746f706c69676874696e63" alt="Stoplight Forest"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Prism Overview&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Prism is a set of packages for API mocking and contract testing with &lt;strong&gt;OpenAPI v2&lt;/strong&gt; (formerly known as Swagger) and &lt;strong&gt;OpenAPI v3.x&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Prism provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mock Servers&lt;/strong&gt;: Life-like mock servers from any API specification document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation Proxy&lt;/strong&gt;: Contract Testing for API consumers and developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive API Specification Support&lt;/strong&gt;: OpenAPI v3.1, OpenAPI v3.0, OpenAPI v2.0 (formerly Swagger) and Postman Collections.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Ways to Use Prism&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Hosted Prism&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Stoplight provides hosted mock servers for convenience so that API consumers can experiment with an API without the need for backend code.&lt;/p&gt;
&lt;p&gt;Use one of these options for instant, hosted mock servers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://stoplight.io/?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=github_repo_prism" rel="nofollow noopener noreferrer"&gt;Stoplight Platform&lt;/a&gt;: Collaborative API Design Platform for designing, developing and documenting APIs with hosted mocking powered by Prism.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stoplight.io/studio/?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=github_repo_prism" rel="nofollow noopener noreferrer"&gt;Stoplight Studio&lt;/a&gt;: Free visual OpenAPI designer that comes integrated with mocking powered by Prism.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Learn more in the &lt;a href="https://docs.stoplight.io/docs/platform/336b74db38c50-work-with-mock-servers" rel="nofollow noopener noreferrer"&gt;hosted Prism documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Self-hosted Prism&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Prism is an open-source…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/stoplightio/prism" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;🧙: Já temos o contrato e o mock da API, que tal criar um código de API para rodar no servidor usando 1 linha de comando? Te apresento meu amigo, &lt;a href="https://openapi-generator.tech/" rel="noopener noreferrer"&gt;Openapi Generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;😒: Da onde ele veio?&lt;/p&gt;

&lt;p&gt;🧙: Do &lt;a href="https://github.com/openapitools/openapi-generator" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;😒: O que ele faz?&lt;/p&gt;

&lt;p&gt;🧙: Gera SDK, código do desenvolvedor e documenta tudo. O melhor amigo do Dev SAGAZ.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/OpenAPITools" rel="noopener noreferrer"&gt;
        OpenAPITools
      &lt;/a&gt; / &lt;a href="https://github.com/OpenAPITools/openapi-generator" rel="noopener noreferrer"&gt;
        openapi-generator
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;OpenAPI Generator&lt;/h1&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;a href="http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.openapitools%22%20AND%20a%3A%22openapi-generator%22" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/880e2dac7ff1b6687978ab40f2689456241a924ee6e28236607b21d2c8f729d3/68747470733a2f2f696d672e736869656c64732e696f2f6d6176656e2d6d657461646174612f762f68747470732f7265706f312e6d6176656e2e6f72672f6d6176656e322f6f72672f6f70656e617069746f6f6c732f6f70656e6170692d67656e657261746f722f6d6176656e2d6d657461646174612e786d6c2e737667" alt="Stable releases in Maven Central"&gt;&lt;/a&gt;
&lt;a href="https://github.com/OpenAPITools/openapi-generator./LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f4f128b18025b723ece3173ca70af4d5ae9346469b2237eeaebbb30bb4963cf7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d417061636865253230322e302d6f72616e6765" alt="Apache 2.0 License"&gt;&lt;/a&gt;
&lt;a href="https://opencollective.com/openapi_generator" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7ef64ef537ef5a47a026972fc955aa83b8c8abb2ffdc627f0de12372de7ea135/68747470733a2f2f696d672e736869656c64732e696f2f6f70656e636f6c6c6563746976652f6261636b6572732f6f70656e6170695f67656e657261746f723f636f6c6f723d6f72616e6765266c6162656c3d4f70656e436f6c6c6563746976652532304261636b657273" alt="Open Collective backers"&gt;&lt;/a&gt;
&lt;a href="https://join.slack.com/t/openapi-generator/shared_invite/zt-12jxxd7p2-XUeQM~4pzsU9x~eGLQqX2g" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/adb2f0048984e2980c6d841e13de72c02fb1d68335997773f4c71c0b22584062/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f536c61636b2d4a6f696e25323074686525323063686174253230726f6f6d2d6f72616e6765" alt="Join the Slack chat room"&gt;&lt;/a&gt;
&lt;a href="https://twitter.com/oas_generator" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0bd5d3834c55e86fbd7dacdd03f093bbe59792536c59e61a302ac7aaf630fef1/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f6f61735f67656e657261746f722e7376673f7374796c653d736f6369616c266c6162656c3d466f6c6c6f77" alt="Follow OpenAPI Generator Twitter account to get the latest update"&gt;&lt;/a&gt;
&lt;a href="https://gitpod.io/#https://github.com/OpenAPITools/openapi-generator" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0d7732e52b61dbd3b8c3e8957089071d3806b2094e698ac3d7505dc628ac69b7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6e74726962757465253230776974682d476974706f642d3930386138353f6c6f676f3d676974706f64" alt="Contribute with Gitpod"&gt;&lt;/a&gt;
&lt;a href="https://conan.io/center/recipes/openapi-generator" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/46cc5e0e6f32a3cb9af8a592306d56ab9027f92166e3148a687beb7cb3d2ad7c/68747470733a2f2f736869656c64732e696f2f636f6e616e2f762f6f70656e6170692d67656e657261746f72" alt="Conan Center"&gt;&lt;/a&gt;
&lt;a href="https://ge.openapi-generator.tech/scans" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/966556624b480f57f0a5fe332b1d0089a2abe01d42af03c46af08f73f9244801/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f526576766564253230757025323062792d446576656c6f636974792d3036413043453f6c6f676f3d477261646c65266c6162656c436f6c6f723d303233303341" alt="Revved up by Develocity"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;a href="https://github.com/OpenAPITools/openapi-generator/tree/master" rel="noopener noreferrer"&gt;Master&lt;/a&gt; (&lt;code&gt;7.10.0&lt;/code&gt;)
&lt;a href="https://app.travis-ci.com/github/OpenAPITools/openapi-generator/builds" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8963897ee7cfae7e2e3ca4014b3a4cacfccf1c1c0309259a9276505a26466acf/68747470733a2f2f6170692e7472617669732d63692e636f6d2f4f70656e415049546f6f6c732f6f70656e6170692d67656e657261746f722e7376673f6272616e63683d6d6173746572267374617475733d706173736564" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://circleci.com/gh/OpenAPITools/openapi-generator" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6e6213e1280db92c4e55d97d69b0e54d1576baeebc1459ad4cf617f5fe194535/68747470733a2f2f636972636c6563692e636f6d2f67682f4f70656e415049546f6f6c732f6f70656e6170692d67656e657261746f722e7376673f7374796c653d736869656c64" alt="Integration Test2"&gt;&lt;/a&gt;
&lt;a href="https://ci.appveyor.com/project/WilliamCheng/openapi-generator" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a404d4dbc45c8c1c9b5ab6e87e069572936c9edcafd6e0e24ce21d160d35a0ee/68747470733a2f2f63692e6170707665796f722e636f6d2f6170692f70726f6a656374732f7374617475732f6769746875622f6f70656e617069746f6f6c732f6f70656e6170692d67656e657261746f723f6272616e63683d6d6173746572267376673d747275652670617373696e67546578743d57696e646f7773253230546573742532302d2532304f4b266661696c696e67546578743d57696e646f7773253230546573742532302d2532304661696c73" alt="Windows Test"&gt;&lt;/a&gt;
&lt;a href="https://app.bitrise.io/app/4a2b10a819d12b67" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a81b7a4ff8f1232a33b3a6a5afd6c43645160adfde5f743929a8c5241b977580/68747470733a2f2f696d672e736869656c64732e696f2f626974726973652f346132623130613831396431326236372f6d61737465723f6c6162656c3d6269747269736525334125323053776966742b342c3526746f6b656e3d383539464d4452385148776162437a77765a4b367651" alt="Bitrise"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;⭐⭐⭐ If you would like to contribute, please refer to &lt;a href="https://github.com/OpenAPITools/openapi-generatorCONTRIBUTING.md" rel="noopener noreferrer"&gt;guidelines&lt;/a&gt; and a list of &lt;a href="https://github.com/openapitools/openapi-generator/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22" rel="noopener noreferrer"&gt;open tasks&lt;/a&gt;. ⭐⭐⭐&lt;/p&gt;
&lt;p&gt;‼️ To migrate from Swagger Codegen to OpenAPI Generator, please refer to the &lt;a href="https://github.com/OpenAPITools/openapi-generatordocs/migration-from-swagger-codegen.md" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt; ‼️&lt;/p&gt;
&lt;p&gt;📔 For more information, please refer to the &lt;a href="https://github.com/openapitools/openapi-generator/wiki" rel="noopener noreferrer"&gt;Wiki page&lt;/a&gt; and &lt;a href="https://github.com/openapitools/openapi-generator/wiki/FAQ" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt; 📔&lt;/p&gt;
&lt;p&gt;📔 The eBook &lt;a href="https://gum.co/openapi_generator_ebook" rel="nofollow noopener noreferrer"&gt;A Beginner's Guide to Code Generation for REST APIs&lt;/a&gt; is a good starting point for beginners 📔&lt;/p&gt;
&lt;p&gt;⚠️ If the OpenAPI spec, templates or any input (e.g. options, environment variables) is obtained from an untrusted source or environment, please make sure you've reviewed these inputs before using OpenAPI Generator to generate the API client, server stub or documentation to avoid potential security issues (e.g. &lt;a href="https://en.wikipedia.org/wiki/Code_injection" rel="nofollow noopener noreferrer"&gt;code injection&lt;/a&gt;). For security vulnerabilities, please contact &lt;a href="https://github.com/OpenAPITools/openapi-generatormailto:team@openapitools.org" rel="noopener noreferrer"&gt;team@openapitools.org&lt;/a&gt;. ⚠️&lt;/p&gt;
&lt;p&gt;‼️ Both "OpenAPI Tools" (&lt;a href="https://OpenAPITools.org" rel="nofollow noopener noreferrer"&gt;https://OpenAPITools.org&lt;/a&gt; - the parent organization of OpenAPI Generator) and "OpenAPI Generator" are not…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/OpenAPITools/openapi-generator" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h5&gt;
  
  
  CLIENT generators
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;ada&lt;/li&gt;
&lt;li&gt;android&lt;/li&gt;
&lt;li&gt;apex&lt;/li&gt;
&lt;li&gt;bash&lt;/li&gt;
&lt;li&gt;c&lt;/li&gt;
&lt;li&gt;clojure&lt;/li&gt;
&lt;li&gt;cpp-qt5-client&lt;/li&gt;
&lt;li&gt;cpp-restsdk&lt;/li&gt;
&lt;li&gt;cpp-tizen&lt;/li&gt;
&lt;li&gt;cpp-ue4 (beta)&lt;/li&gt;
&lt;li&gt;csharp&lt;/li&gt;
&lt;li&gt;csharp-dotnet2 (deprecated)&lt;/li&gt;
&lt;li&gt;csharp-netcore&lt;/li&gt;
&lt;li&gt;dart&lt;/li&gt;
&lt;li&gt;dart-dio&lt;/li&gt;
&lt;li&gt;dart-jaguar&lt;/li&gt;
&lt;li&gt;eiffel&lt;/li&gt;
&lt;li&gt;elixir&lt;/li&gt;
&lt;li&gt;elm&lt;/li&gt;
&lt;li&gt;erlang-client&lt;/li&gt;
&lt;li&gt;erlang-proper&lt;/li&gt;
&lt;li&gt;flash&lt;/li&gt;
&lt;li&gt;go&lt;/li&gt;
&lt;li&gt;go-experimental (experimental)&lt;/li&gt;
&lt;li&gt;groovy&lt;/li&gt;
&lt;li&gt;haskell-http-client&lt;/li&gt;
&lt;li&gt;java&lt;/li&gt;
&lt;li&gt;javascript&lt;/li&gt;
&lt;li&gt;javascript-apollo (beta)&lt;/li&gt;
&lt;li&gt;javascript-closure-angular&lt;/li&gt;
&lt;li&gt;javascript-flowtyped&lt;/li&gt;
&lt;li&gt;jaxrs-cxf-client&lt;/li&gt;
&lt;li&gt;jmeter&lt;/li&gt;
&lt;li&gt;k6 (beta)&lt;/li&gt;
&lt;li&gt;kotlin&lt;/li&gt;
&lt;li&gt;lua (beta)&lt;/li&gt;
&lt;li&gt;nim (beta)&lt;/li&gt;
&lt;li&gt;objc&lt;/li&gt;
&lt;li&gt;ocaml&lt;/li&gt;
&lt;li&gt;perl&lt;/li&gt;
&lt;li&gt;php&lt;/li&gt;
&lt;li&gt;powershell (beta)&lt;/li&gt;
&lt;li&gt;python&lt;/li&gt;
&lt;li&gt;python-experimental (experimental)&lt;/li&gt;
&lt;li&gt;r&lt;/li&gt;
&lt;li&gt;ruby&lt;/li&gt;
&lt;li&gt;rust&lt;/li&gt;
&lt;li&gt;scala-akka&lt;/li&gt;
&lt;li&gt;scala-gatling&lt;/li&gt;
&lt;li&gt;scala-httpclient-deprecated (deprecated)&lt;/li&gt;
&lt;li&gt;scala-sttp (beta)&lt;/li&gt;
&lt;li&gt;scalaz&lt;/li&gt;
&lt;li&gt;swift4-deprecated (deprecated)&lt;/li&gt;
&lt;li&gt;swift5 (beta)&lt;/li&gt;
&lt;li&gt;typescript (experimental)&lt;/li&gt;
&lt;li&gt;typescript-angular&lt;/li&gt;
&lt;li&gt;typescript-angularjs-deprecated (deprecated)&lt;/li&gt;
&lt;li&gt;typescript-aurelia&lt;/li&gt;
&lt;li&gt;typescript-axios&lt;/li&gt;
&lt;li&gt;typescript-fetch&lt;/li&gt;
&lt;li&gt;typescript-inversify&lt;/li&gt;
&lt;li&gt;typescript-jquery&lt;/li&gt;
&lt;li&gt;typescript-node&lt;/li&gt;
&lt;li&gt;typescript-redux-query&lt;/li&gt;
&lt;li&gt;typescript-rxjs &lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  SERVER generators
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;ada-server&lt;/li&gt;
&lt;li&gt;aspnetcore&lt;/li&gt;
&lt;li&gt;cpp-pistache-server&lt;/li&gt;
&lt;li&gt;cpp-qt5-qhttpengine-server&lt;/li&gt;
&lt;li&gt;cpp-restbed-server&lt;/li&gt;
&lt;li&gt;csharp-nancyfx&lt;/li&gt;
&lt;li&gt;erlang-server&lt;/li&gt;
&lt;li&gt;fsharp-functions (beta)&lt;/li&gt;
&lt;li&gt;fsharp-giraffe-server (beta)&lt;/li&gt;
&lt;li&gt;go-gin-server&lt;/li&gt;
&lt;li&gt;go-server&lt;/li&gt;
&lt;li&gt;graphql-nodejs-express-server&lt;/li&gt;
&lt;li&gt;haskell&lt;/li&gt;
&lt;li&gt;java-inflector&lt;/li&gt;
&lt;li&gt;java-msf4j&lt;/li&gt;
&lt;li&gt;java-pkmst&lt;/li&gt;
&lt;li&gt;java-play-framework&lt;/li&gt;
&lt;li&gt;java-undertow-server&lt;/li&gt;
&lt;li&gt;java-vertx&lt;/li&gt;
&lt;li&gt;java-vertx-web (beta)&lt;/li&gt;
&lt;li&gt;jaxrs-cxf&lt;/li&gt;
&lt;li&gt;jaxrs-cxf-cdi&lt;/li&gt;
&lt;li&gt;jaxrs-cxf-extended&lt;/li&gt;
&lt;li&gt;jaxrs-jersey&lt;/li&gt;
&lt;li&gt;jaxrs-resteasy&lt;/li&gt;
&lt;li&gt;jaxrs-resteasy-eap&lt;/li&gt;
&lt;li&gt;jaxrs-spec&lt;/li&gt;
&lt;li&gt;kotlin-server&lt;/li&gt;
&lt;li&gt;kotlin-spring&lt;/li&gt;
&lt;li&gt;kotlin-vertx (beta)&lt;/li&gt;
&lt;li&gt;nodejs-express-server (beta)&lt;/li&gt;
&lt;li&gt;php-laravel&lt;/li&gt;
&lt;li&gt;php-lumen&lt;/li&gt;
&lt;li&gt;php-silex-deprecated (deprecated)&lt;/li&gt;
&lt;li&gt;php-slim-deprecated (deprecated)&lt;/li&gt;
&lt;li&gt;php-slim4&lt;/li&gt;
&lt;li&gt;php-symfony&lt;/li&gt;
&lt;li&gt;php-ze-ph&lt;/li&gt;
&lt;li&gt;python-aiohttp&lt;/li&gt;
&lt;li&gt;python-blueplanet&lt;/li&gt;
&lt;li&gt;python-flask&lt;/li&gt;
&lt;li&gt;ruby-on-rails&lt;/li&gt;
&lt;li&gt;ruby-sinatra&lt;/li&gt;
&lt;li&gt;rust-server&lt;/li&gt;
&lt;li&gt;scala-akka-http-server (beta)&lt;/li&gt;
&lt;li&gt;scala-finch&lt;/li&gt;
&lt;li&gt;scala-lagom-server&lt;/li&gt;
&lt;li&gt;scala-play-server&lt;/li&gt;
&lt;li&gt;scalatra&lt;/li&gt;
&lt;li&gt;spring &lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  DOCUMENTATION generators
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;asciidoc&lt;/li&gt;
&lt;li&gt;cwiki&lt;/li&gt;
&lt;li&gt;dynamic-html&lt;/li&gt;
&lt;li&gt;html&lt;/li&gt;
&lt;li&gt;html2&lt;/li&gt;
&lt;li&gt;markdown (beta)&lt;/li&gt;
&lt;li&gt;openapi&lt;/li&gt;
&lt;li&gt;openapi-yaml&lt;/li&gt;
&lt;li&gt;plantuml (beta) &lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  SCHEMA generators
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;avro-schema (beta)&lt;/li&gt;
&lt;li&gt;mysql-schema &lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  CONFIG generators
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;apache2&lt;/li&gt;
&lt;li&gt;graphql-schema&lt;/li&gt;
&lt;li&gt;protobuf-schema (beta) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Que tal dar o primeiro passo? Se esta na duvida olha essa musica que fizeram para quem não quis arriscar:&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-ab2"&gt;Introduçao&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-centralizacao-2ebm/edit"&gt;Centralização&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Contrato da API&lt;/li&gt;
&lt;li&gt;Diretrizes de estilo&lt;/li&gt;
&lt;li&gt;Reutilização&lt;/li&gt;
&lt;li&gt;Automação&lt;/li&gt;
&lt;li&gt;Versionamento&lt;/li&gt;
&lt;li&gt;Política de descontinuação&lt;/li&gt;
&lt;li&gt;Rastreamento / Observabilidade&lt;/li&gt;
&lt;li&gt;Descoberta de API&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Referencial
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://polgovpro.blog/2020/07/27/adaptive-strategy/" rel="noopener noreferrer"&gt;Adaptive Strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://swagger.io/resources/articles/api-development-with-openapi-swagger/" rel="noopener noreferrer"&gt;Launching a Scalable API Program with OpenAPI: Optimize Your API Workflow with OpenAPI &amp;amp; Swagger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stoplight.io/api-design-guide/basics/" rel="noopener noreferrer"&gt;What is API Design?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gohorseprocess.com.br/extreme-go-horse-xgh/" rel="noopener noreferrer"&gt;eXtreme Go Horse (XGH)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;





&lt;div class="ltag__user ltag__user__id__426430"&gt;
    &lt;a href="/juscelior" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F426430%2Fab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt="juscelior image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/juscelior"&gt;Pode me chamar de Juscélio Reis&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/juscelior"&gt; Professional in constant learning, software developer with almost 10 years of career, researcher on distributed systems and information security. Strong experience in software development with C #&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>api</category>
      <category>governance</category>
      <category>development</category>
      <category>devops</category>
    </item>
    <item>
      <title> [Série] Governança de API: Centralização</title>
      <dc:creator>Pode me chamar de Juscélio Reis</dc:creator>
      <pubDate>Tue, 28 Jul 2020 02:19:30 +0000</pubDate>
      <link>https://forem.com/devzwiz/serie-governanca-de-api-centralizacao-2ebm</link>
      <guid>https://forem.com/devzwiz/serie-governanca-de-api-centralizacao-2ebm</guid>
      <description>&lt;p&gt;Dando continuidade a nossa serie sobre Governança de API, vamos falar de Centralização. Quando queremos organizar a bagunça sempre lembro dessa fala do &lt;em&gt;Deming&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Não se gerencia o que não se mede,&lt;br&gt;
não se mede o que não se define,&lt;br&gt;
não se define &lt;strong&gt;o que não se entende&lt;/strong&gt;,&lt;br&gt;
e não há sucesso no que não se gerencia&lt;br&gt;
-- William Edwards Deming&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Olhando atentamente essa fala, é possível inferir que para alcançar o sucesso é de extrema importância entender o contexto do problema e sua nuances. Não será diferente com o assunto desse artigo, afinal vivemos em um tempo complexo. A cada minuto que passa surge uma nova tecnologia, um novo serviço e uma nova forma de pensar, antigamente era mais simples, os sistemas eram todos construido para atender todas as necessidades, vulgo monolito, e todas as regras de negócios podiam ser extraídas de um único local. Atualmente estamos implementando microserviços, mesmo que não seja preciso &lt;a href="https://www.infoq.com/br/news/2020/06/monolith-decomposition-newman/"&gt;leia mais sobre aqui&lt;/a&gt;. A quantidade de API ou serviços no meio corporativo só tem aumentado. Imagina quando começar a ser tudo (&lt;em&gt;serverless&lt;/em&gt;)[&lt;a href="https://aws.amazon.com/pt/serverless/"&gt;https://aws.amazon.com/pt/serverless/&lt;/a&gt;] 🤪.&lt;/p&gt;

&lt;p&gt;Sem levantar as nuances de certos contextos bem específicos do seu sistema. A forma mais simples pra iniciar o processo de entendimento do seu ambiente é criar uma lista com todas as APIs internas e externas. Informando uma breve descrição sobre características chaves para que qualquer ser humano consiga entender qual a utilidade e quando precisa consumir sua API. Essa descrição deve conter pelo menos os campos abaixo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recurso&lt;/strong&gt;: descreve o motivo dessa API ter sido projetada, e o que ela consegue entregar, usando uma linguagem que os seres humanos, leigos, possam digerir;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estrutura&lt;/strong&gt;: uma descrição esquemática das APIs, incluindo URIs, estruturas de dados, segurança, etc. Podemos citar como exemplo aqui o &lt;a href="https://www.openapis.org/"&gt;OpenAPI&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacidade&lt;/strong&gt;: qual a quantidade de requisições que essa api deve suportar, quantas requisições seu cliente já consumiu;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensibilidade&lt;/strong&gt;: a API consome ou expõe dados que possam estar sujeitos a restrições regulatórias ou de privacidade, como dados de cartão de pagamento, dados de identificação pessoal e assim por diante.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para tal inventario é dado o nome de &lt;em&gt;Catalogo de API&lt;/em&gt; (vou usar esse termo daqui pra frente) ou &lt;em&gt;Registro de API&lt;/em&gt;. Como exemplo de catalogo de API bem feito cito o &lt;a href="https://www.programmableweb.com/"&gt;ProgrammableWeb&lt;/a&gt; e o &lt;a href="https://rapidapi.com/"&gt;RapidAPI&lt;/a&gt; como exemplo a ser copiado.&lt;/p&gt;

&lt;p&gt;O catalogo de API também ajuda a equipe de governança a criar e aplicar políticas. Existem alguns modelos para a construção dessa equipe, todos com o intuito de chegar no estado da arte em Governança de API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralizado&lt;/strong&gt;: Toda alteração arquitetural, desde a implementação de novos recursos até a aplicação ou introdução de novos elementos no cenário arquitetônico, sempre são revisadas e aprovadas por uma equipe centralizada. Esse modelo tem um grande problema de escalabilidade, já que isso pode fazer com que a equipe se torne um gargalo devido ao alto nível de demandas impostas a elas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Descentralizado&lt;/strong&gt;: Similar ao modelo anterior, mas formado por mais de uma equipe, menor, e essa possuindo autonomia para avaliar e validar certos aspectos da arquitetura, seja para um aplicativo específico ou para um conjunto de aplicativos relacionados. Agora o problema desse modelo é coordenar essas equipes, evitando que mudanças de uma equipe afete a outra equipe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribuído&lt;/strong&gt;: Formado por equipes especialistas em um conjunto de produtos e, portanto, responsáveis ​​por eles. O conhecimento comercial e os aspectos de governança são cruciais para garantir que os controles corretos estejam em vigor.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Aqui eu indico o vídeo da Sensedia com o tema &lt;strong&gt;Repensando a Governança de APIs&lt;/strong&gt; &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Pviw622zd0E"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tenha um certo cuidado ao escolher o melhor modelo para sua organização. Como foi falado no &lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-ab2"&gt;post anterior&lt;/a&gt;, comece devagar e vai adaptando a sua realidade, reforçando as boas práticas e mudando o que não deu certo para o seu contexto.&lt;/p&gt;

&lt;p&gt;Tome cuidado para não confundir catalogo de API com o portal do desenvolvedor, sob a ótica da governança todas as APIs são importantes, se é interna ou externa, ela deve estar no inventario. E o acesso a esse inventario deve ser divulgado para toda a empresa, principalmente para a área de negócio. Eles podem visualizar o que já existem e definir uma estratégia para consumir essas APIs de acordo com suas necessidades.&lt;/p&gt;

&lt;p&gt;Mas um portal do desenvolvedor pode ser um produto, e como produto precisamos entender qual o seu publico alvo. Aqui é possível distinguir 3 tipos de publico alvo que uma organização geralmente possui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Equipes internas&lt;/strong&gt;: O objetivo inicial é permitir que suas equipes internas criem novas funcionalidades e aplicativos sobre suas APIs. Ao pensar no catalogo de API para equipes internas é importante pensar como que essas equipes vão consumir suas APIs, a experiência do desenvolvedor aqui é muito importante para ganhar escala. &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/rokam" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vGaSZYCg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--_0Lo68io--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/426431/6a724e76-cc55-4973-906b-3163ea60cd7a.jpeg" alt="rokam image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/devzwiz/the-wiz-way-to-build-technological-solutions-4b8b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;The Wiz way to build technological solutions&lt;/h2&gt;
      &lt;h3&gt;Lucas Mindêllo ・ Jul  7 '20 ・ 3 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#microservices&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#governance&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#agile&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parceiros e/ou Clientes&lt;/strong&gt;: Seus parceiros de negócios e clientes são as próximas partes interessadas que podem fornecer mais valor agregado a sua organização por meio de APIs. A API do seu parceiro pode integrar-se ao aplicativo de RH de um cliente para otimizar as informações dos funcionários ou fornecer um benefício diferenciado para o seu cliente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Desenvolvedores de terceiros&lt;/strong&gt;: A etapa final é disponibilizar suas APIs para o público em geral e monetizar com isso 🤑. Se ainda não parou para pensar em ganhar dinheiro. Gaste um tempo e o explore esses sites aqui &lt;a href="https://www.programmableweb.com/"&gt;ProgrammableWeb&lt;/a&gt; e o &lt;a href="https://rapidapi.com/"&gt;RapidAPI&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mantendo a inovação constante
&lt;/h3&gt;

&lt;p&gt;É possível manter um fluxo de inovação constante, e apoiar a estratégia da sua organização? Para chegar nesse nível de maturidade é fundamental oferecer sustentação para tipo de público alvo, e manter uma alta taxa de inovação nesses portais, talvez até uma equipe dedicada exclusivamente na entrega dessas inovações. &lt;/p&gt;

&lt;p&gt;Construir esses portais ajudam a entregar diferencial para os desenvolvedores que procuram APIs com o intuito de agregar valor no seu produto. A inovação e o diferencial desse produto aparece em como você pensa na forma que seu publico vai solicitar acesso, gerar suas chaves de API ou tokens OAuth. Como o desenvolvedor vai consumir sua API se será através de um contrato como Swagger ou usando um SDK feito por você.&lt;/p&gt;

&lt;p&gt;Não fique preso apenas no inventario para o catalogo de APIs. Pense em como será a experiência do desenvolvedor, como esse produto vai ajudar nas entregas do dia a dia desse desenvolvedor. Só uma sugestão, é possível disponibilizar SDKs para qualquer tipo de linguagem de programação, um canal de ajuda, suporte, informações dos logs de alterações, mudança de contrato ou quando essa API vai deixar de ser suportada pela organização.&lt;/p&gt;

&lt;p&gt;Agora que possui essas informações centralizadas é possível realizar uma analise do impacto de uma determina alteração, visualizar as dependências de cada API e conseguir enxergar a como estão sendo expostos os campos mais sensíveis. Existem ferramentas como o &lt;a href="https://stoplight.io/api-visibility/"&gt;Stoplight&lt;/a&gt;, que entrega de uma forma visual essas visualizações. Para conseguir extrair o máximo dessas ferramentas será preciso entender o conceito de &lt;strong&gt;Contrato da API&lt;/strong&gt;, e este é o assunto do próximo artigo dessa serie.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-ab2"&gt;Introduçao&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Centralização&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-contrato-da-api-2dd0"&gt;Contrato da API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Diretrizes de estilo&lt;/li&gt;
&lt;li&gt;Reutilização&lt;/li&gt;
&lt;li&gt;Automação&lt;/li&gt;
&lt;li&gt;Versionamento&lt;/li&gt;
&lt;li&gt;Política de descontinuação&lt;/li&gt;
&lt;li&gt;Rastreamento / Observabilidade&lt;/li&gt;
&lt;li&gt;Descoberta de API&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Referencial
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nordicapis.com/api-governance-how-important-is-it-for-api-strategy/"&gt;API Governance: How Important Is It for API Strategy?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://swagger.io/resources/articles/best-practices-in-api-governance/"&gt;Best Practices in API Governance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-ab2"&gt;[Série] Governança de API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nordicapis.com/ebooks/the-api-economy/"&gt;The API Economy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nordicapis.com/what-to-consider-when-building-your-api-strategy/"&gt;What to Consider When Building Your API Strategy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;





&lt;div class="ltag__user ltag__user__id__426430"&gt;
  
    .ltag__user__id__426430 .follow-action-button {
      background-color: #008000 !important;
      color: #dce9f3 !important;
      border-color: #008000 !important;
    }
  
    &lt;a href="/juscelior" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4xok3liq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--nZjGgy2R--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/426430/ab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt="juscelior image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/juscelior"&gt;Pode me chamar de Juscélio Reis&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/juscelior"&gt; Professional in constant learning, software developer with almost 10 years of career, researcher on distributed systems and information security. Strong experience in software development with C #&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>api</category>
      <category>governance</category>
      <category>development</category>
      <category>devops</category>
    </item>
    <item>
      <title>[Série] Governança de API</title>
      <dc:creator>Pode me chamar de Juscélio Reis</dc:creator>
      <pubDate>Tue, 21 Jul 2020 01:30:42 +0000</pubDate>
      <link>https://forem.com/devzwiz/serie-governanca-de-api-ab2</link>
      <guid>https://forem.com/devzwiz/serie-governanca-de-api-ab2</guid>
      <description>&lt;p&gt;Nos últimos meses tenho notado um aumento substancial da utilização do termo API. Empresas estão cada dia mais criando e consumindo APIs e a procura por desenvolvedores que sabem construir APIs também tem crescido. Existem inúmeras maneiras de construir e fornecer uma API, para isso podemos citar grandes empresas que possuem soluções prontas e de alto custo visando entregar uma API no menor tempo possível, ou podemos construir do zero a um baixo custo nossas próprias soluções e entregar uma API gastando um tempo razoável.&lt;/p&gt;

&lt;p&gt;Mas a maioria dessas soluções não são capazes de entregar um recurso fundamental: Gerenciamento do Ciclo de vida do desenvolvimento. Um desenvolvedor passa algum tempo criando APIs úteis e robustas, mas acaba lutando com a evolução orgânica do seu código e com as mudanças que o meio negocial pode impor no desenvolvimento, como a famosa frase: precisamos dessa alteração para amanhã. Será se esse desenvolvedor é capaz de informa qual o verdadeiro impacto que uma simples mudança de parâmetro pode trazer para todos os clientes?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👾🎤 Isso não faz sentido, o que mais existe por ai são ferramentas de ALM, DevOps ou acompanhamento de projeto.&lt;br&gt;
-- Leitor ansioso&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para esses leitores, só posso responder que continuem lendo. E que o foco desse artigo é &lt;strong&gt;Governança de APIs&lt;/strong&gt;. E por ser um tema bem especifico, precisamos de ferramentas bem especificas. É diferente do que construir um software que vai rodar apenas no navegador ou no desktop. Deixa apresentar como é a construção de uma API sem o gerenciamento do ciclo de vida do desenvolvimento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bjjo0zw4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/02yf0qxepz7zywx090sp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bjjo0zw4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/02yf0qxepz7zywx090sp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para as empresas cuja a estratégia de negócio tem como objetivo entregar API para um mercado em potencial, a governança é uma necessidade. Não sabe do que estou falando sugiro que naveguem no site &lt;a href="https://www.programmableweb.com/"&gt;ProgrammableWeb&lt;/a&gt; ou procure pelos temas &lt;a href="https://www.infomoney.com.br/consumo/open-banking-o-que-e-e-como-funciona/"&gt;Open Banking&lt;/a&gt; ou &lt;a href="https://www.revistaapolice.com.br/2019/10/open-insurance-entenda-o-conceito-e-sua-aplicacao/"&gt;Open Insurance&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atividades da governança de API
&lt;/h2&gt;

&lt;p&gt;Foi falado um monte sobre governança de API e gerenciamento do ciclo de vida do desenvolvimento focando na entra de API. Mas afinal o que seria isso, quais são as atividades que diferenciam de uma construção de software para &lt;em&gt;web&lt;/em&gt; ou &lt;em&gt;desktop&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Primeiro preciso fazer uma pergunta a você; você sabe onde estão todas as APIs da sua empresa? Nesse exato momento consegue informar quais clientes estão consumindo suas APIs?&lt;/p&gt;

&lt;p&gt;Nesse momento consigo definir a Governança de API como a disciplina que vai desenvolver um trabalho para entender onde as pessoas estão, ferramentas, serviços, habilidades, melhores e piores práticas. E cruzar com o anseio e desejos dos outros setores da empresa, com o objetivo de construir uma ponte entre o momento atual da empresa com o que pode acabar sendo uma futura estratégia de governança de API.&lt;/p&gt;

&lt;p&gt;De nada adianta implantar uma solução completa e robusta que já foi validada em outros times, se não trabalhar pessoas, ferramentas, processos e cultura dos envolvidos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A cultura come a estratégia no café da manhã&lt;br&gt;
-- Peter Drucker &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A governança é especialmente benéfica para organizações que possuem um trabalho de construção de API ou arquiteturas de microsserviços, entregando consistência dos seus serviços para toda a organização. Além de ajudar a evitar problemas como código duplicado, acoplamento rígido entre componentes, falta de confiabilidade e economia.&lt;/p&gt;

&lt;p&gt;Afinal o desejo de quem trabalha no time de governança é que as pessoas se importem com o design da API e estejam abertas a aprender como outras pessoas estão projetando suas APIs. E que os próprio time consiga defender o valor que um bom projeto pode agregar ao negocio em vez de simplesmente responder um ticket do JIRA. Pois o ticket não diz nada sobre a API ser bem projetada e consistente com outras equipes, a governança entre aqui.&lt;/p&gt;

&lt;p&gt;Esse foi apenas o primeiro artigo da serie sobre Governança de API. Para os próximos episódios vamos abordar os seguintes temas com a visão da governança.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Introdução&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-centralizacao-2ebm"&gt;Centralização&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devzwiz/serie-governanca-de-api-contrato-da-api-2dd0"&gt;Contrato da API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Diretrizes de estilo&lt;/li&gt;
&lt;li&gt;Reutilização&lt;/li&gt;
&lt;li&gt;Automação&lt;/li&gt;
&lt;li&gt;Versionamento&lt;/li&gt;
&lt;li&gt;Política de descontinuação&lt;/li&gt;
&lt;li&gt;Rastreamento / Observabilidade&lt;/li&gt;
&lt;li&gt;Descoberta de API&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Referencial
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nordicapis.com/ebooks/the-api-economy/"&gt;Basic API Design Guidelines Are Your First Step Towards API Governance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://swagger.io/resources/articles/best-practices-in-api-governance/"&gt;Best Practices in API Governance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://apievangelist.com/2020/01/21/i-think-we-will-have-to-embrace-chaos-with-the-future-of-apis/"&gt;I Think We Will Have To Embrace Chaos With the Future of APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@juscelioreis/por-que-devemos-come%C3%A7ar-nossas-apis-pelo-contrato-ee1de70af8b3"&gt;Por que devemos começar nossas APIs pelo contrato?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://swagger.io/resources/articles/adopting-an-api-first-approach/"&gt;Understanding  the API-First Approach to Building Products&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://apievangelist.com/2018/02/06/you-have-to-know-where-all-your-apis-are-before-you-can-deliver-on-api/"&gt;You Have to Know Where All Your APIs Are Before You Can Deliver On API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;





&lt;div class="ltag__user ltag__user__id__426430"&gt;
  
    .ltag__user__id__426430 .follow-action-button {
      background-color: #008000 !important;
      color: #dce9f3 !important;
      border-color: #008000 !important;
    }
  
    &lt;a href="/juscelior" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4xok3liq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--nZjGgy2R--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/426430/ab8d100e-70ca-42c4-a5f8-52fc203e22bf.jpg" alt="juscelior image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/juscelior"&gt;Pode me chamar de Juscélio Reis&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/juscelior"&gt; Professional in constant learning, software developer with almost 10 years of career, researcher on distributed systems and information security. Strong experience in software development with C #&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>api</category>
      <category>governance</category>
      <category>development</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Wiz way to build technological solutions</title>
      <dc:creator>Lucas Mindêllo</dc:creator>
      <pubDate>Tue, 07 Jul 2020 20:47:47 +0000</pubDate>
      <link>https://forem.com/devzwiz/the-wiz-way-to-build-technological-solutions-4b8b</link>
      <guid>https://forem.com/devzwiz/the-wiz-way-to-build-technological-solutions-4b8b</guid>
      <description>&lt;p&gt;Hello, I'm Lucas Mindêllo, an IT Manager of Wiz and I'm responsible to define the Wiz way of working in technological solutions. So, I need to provide you a background of Wiz challenges that I'm trying to address.&lt;/p&gt;

&lt;p&gt;We are Wiz, we sell insurance and financial products using our business units. So, we have an initiative shaping the way all our sales structures works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qsvQK7fD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6vozev3na7e2o7dacoyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qsvQK7fD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6vozev3na7e2o7dacoyl.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For that, we're organized in Squads where each one looks for a singular business unit, each one with different needs and, as head of the development team, I need to help our Dev team to be able to work, build solutions with a corporate vision, and delivering value on every sprint. By the way, we mainly use Scrum, although that needs another article.&lt;/p&gt;

&lt;h1&gt;
  
  
  How we keep governance in our development?
&lt;/h1&gt;

&lt;p&gt;I believe that we have three main pillars to address, a frame to deliver the same vision to all developers, a well-known process and management on those pillars. This article will focus on the development frame.&lt;/p&gt;

&lt;p&gt;To deliver that, we need to level some ground premises:&lt;/p&gt;

&lt;p&gt;We develop using microservices architecture;&lt;br&gt;
We deliver autonomy to all squads;&lt;br&gt;
We need to level knowledge with our DEVs;&lt;br&gt;
We need to maintain corporative system governance.&lt;br&gt;
And this frame results in white-label solutions for our costumers. Based on components and low effort to change the look-n-feel.&lt;/p&gt;

&lt;h1&gt;
  
  
  What a component represents?
&lt;/h1&gt;

&lt;p&gt;Besides the frontend component concept, we've extrapolated it to backend/frontend connection. We did that, somehow a component is configurable to any similar need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pM1_fJsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8mjmb0yaoallue3n1lit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pM1_fJsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8mjmb0yaoallue3n1lit.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above represents a simple component that has the CRM and two databases as sources. We believe that a project standard for components and pages is enough to address the governance needs for the frontend, although we need to better shape the backend architecture.&lt;/p&gt;

&lt;h1&gt;
  
  
  How we address the backend governance?
&lt;/h1&gt;

&lt;p&gt;Focused to maintain the squads' autonomy and reuse the majority of our developed code, we have split our microservices into two categories: Wiz Services and Squad Services.&lt;/p&gt;

&lt;p&gt;We've limited to Wiz Services only corporative business rules, somehow any business unit should use the service routes seamless. With that in mind, we had to enforce a higher code review policy and deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vj-IHzaI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7atzip8cnf8pusorgshi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vj-IHzaI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7atzip8cnf8pusorgshi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we need all DEVs to be able to evolve our Wiz Services, we've defined .NET Core as our standard framework for Wiz Services.&lt;/p&gt;

&lt;p&gt;To address the Triple A need on every element connection, we've developed a SSO API, based on OpenID and JWT token. We did that someway the same SSO solution is used for a user or service identification.&lt;/p&gt;

&lt;p&gt;Another auxiliary service is Wiz Log. This solution is focused to log our business events. Our main objective is to be able to keep track of some business events and to be able to analise that information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cchlKwKM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w2h9hx4m3qez1gohp3om.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cchlKwKM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w2h9hx4m3qez1gohp3om.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think that the Wiz Log can be explained in another article.&lt;/p&gt;

&lt;p&gt;All of that is unecessary if we don't standardize our microservice code.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is the Wiz Microservice Project Standard?
&lt;/h1&gt;

&lt;p&gt;We think that is worth to split the application in domain layers, that way we've made our interpretation of DDD (Domain Driven Design). We've split it in 3 layers, API, domain and infra.&lt;/p&gt;

&lt;p&gt;I think that the success of a well-designed API depends on a good domain definition. The Domain layer is where we define what are the entities that our microservice will represent. If we take a CRM-API as reference, one main entity is Client and every client has some attributes that is common to all business units needs. That's the main responsibility of the Domain Layer.&lt;/p&gt;

&lt;p&gt;The Infra Layer should translate the API entity to the datasource elements. Using the same API-CRM as an example, in this layer a client should be represented as an Account and Contact in Salesforce. This way, for any reason, if we need to integrate our API to another CRM, we just need to translate those entities to that CRM.&lt;/p&gt;

&lt;p&gt;And finally, the API Layer is the presentation layer. It's where we expose our REST endpoints. By the way, we use RESTFull on our microservices, which improves our development velocity.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I think we're on a good way to develop great solutions with governance and keeping a good velocity.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>governance</category>
      <category>agile</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
