<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Caramelo da TI</title>
    <description>The latest articles on DEV Community by Caramelo da TI (@caramelo-ti).</description>
    <link>https://dev.to/caramelo-ti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3588450%2F469a649c-9ab2-43f6-9381-2611ce0c3050.png</url>
      <title>DEV Community: Caramelo da TI</title>
      <link>https://dev.to/caramelo-ti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/caramelo-ti"/>
    <language>en</language>
    <item>
      <title>mcp-scan: a ferramenta que revela riscos que você não vê</title>
      <dc:creator>Caramelo da TI</dc:creator>
      <pubDate>Sat, 29 Nov 2025 01:31:03 +0000</pubDate>
      <link>https://dev.to/caramelo-ti/mcp-scan-a-ferramenta-que-revela-riscos-que-voce-nao-ve-3dci</link>
      <guid>https://dev.to/caramelo-ti/mcp-scan-a-ferramenta-que-revela-riscos-que-voce-nao-ve-3dci</guid>
      <description>&lt;p&gt;Recentemente saiu a nova edição do &lt;strong&gt;Tech Radar da Thoughtworks&lt;/strong&gt; e, dando uma olhada no quadrante de ferramentas no anel &lt;em&gt;Trial&lt;/em&gt;, me deparei com uma recomendação de um colega: o servidor MCP &lt;strong&gt;Context7&lt;/strong&gt;. A proposta é bem interessante porque permite que um agente consulte a documentação real de uma tecnologia em vez de simplesmente “chutar” — evitando aquelas alucinações ou respostas mágicas que parecem existir… mas só na &lt;em&gt;imaginação&lt;/em&gt; do modelo.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0b9pn2zk9eanjrl6hu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0b9pn2zk9eanjrl6hu5.png" alt="Context7 Tech Rada" width="800" height="835"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas aí surgiu outra dúvida: com tantas recomendações de servidores MCP diferentes, até que ponto é seguro ir adicionando novas tools no seu cliente?&lt;/p&gt;

&lt;p&gt;Pesquisando um pouco mais, voltei ao mesmo Tech Radar, mas agora no anel &lt;em&gt;Assess&lt;/em&gt;, onde encontrei o &lt;strong&gt;mcp-scan&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;O &lt;strong&gt;mcp-scan&lt;/strong&gt; ajuda a identificar vulnerabilidades de segurança como &lt;em&gt;prompt injection&lt;/em&gt;, &lt;em&gt;tool poisoning&lt;/em&gt; e &lt;em&gt;toxic flows&lt;/em&gt;. Ele também permite monitorar o tráfego entre agentes e servidores MCP, ajudando a entender como as tools se comportam em tempo real e evitando ataques escondidos no background.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configurando o Context7 no Github Copilot pra Jetbrains
&lt;/h3&gt;

&lt;p&gt;A configuração é bem simples. O mais recomendado é gerar uma chave de API criando uma conta na &lt;a href="https://context7.com" rel="noopener noreferrer"&gt;Context7&lt;/a&gt;, assim você ganha limites de uso mais generosos.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuração visual
&lt;/h4&gt;

&lt;p&gt;Nas IDEs da JetBrains, abra a janela do GitHub Copilot e clique no ícone de ferramentas (Configure Tools).&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss6scamy5qy5atuevdo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss6scamy5qy5atuevdo9.png" alt="config_tool" width="800" height="396"&gt;&lt;/a&gt;&lt;br&gt;
Depois clique em Add More Tools.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogvp3dgecxqoj5nig1bl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogvp3dgecxqoj5nig1bl.png" alt="add_more_tool" width="546" height="156"&gt;&lt;/a&gt;&lt;br&gt;
Isso vai abrir o arquivo de configuração com a lista de servidores MCP disponíveis para o Copilot.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuração via terminal
&lt;/h4&gt;

&lt;p&gt;Abra o arquivo mcp.json, que fica em: &lt;code&gt;~/.config/github-copilot/intellij/mcp.json&lt;/code&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vi ~/.config/github-copilot/intellij/mcp.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com o arquivo aberto, basta adicionar a configuração do servidor Context7:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"context7"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.context7.com/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json, text/event-stream"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"get-library-docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resolve-library-id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Nos exemplos da documentação o header &lt;code&gt;Accept&lt;/code&gt; não aparece, mas precisei adicionar porque o servidor também usa &lt;code&gt;text/event-stream&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depois disso o agente já consegue usar as tools do Context7. A própria documentação recomenda adicionar uma instrução global pedindo para sempre consultar a documentação quando necessário.&lt;br&gt;
Isso pode ser feito em: &lt;code&gt;~/.config/github-copilot/intellij/global-copilot-instructions.md&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Usando &lt;code&gt;uv&lt;/code&gt; com &lt;code&gt;mcp-scan&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;O &lt;strong&gt;uv&lt;/strong&gt; é um gerenciador e executor de ambientes Python que facilita muito instalar ferramentas como o &lt;strong&gt;mcp-scan&lt;/strong&gt;. A instalação é bem direta, basta seguir o &lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="noopener noreferrer"&gt;guia oficial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Com o &lt;strong&gt;uv&lt;/strong&gt; instalado, para escanear basta rodar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvx mcp-scan@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para escanear um servidor específico, como o do GitHub Copilot para JetBrains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mcp-scan ~/.config/github-copilot/intellij/mcp.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como configuramos o servidor MCP da Context7, você deve encontrar uma saída como abaixo:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnnlbcr9lvrzb7k9tpmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnnlbcr9lvrzb7k9tpmm.png" alt="context7 scan" width="674" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Também dá para usar o mcp-scan como proxy, monitorando o tráfego em tempo real entre cliente e servidor MCP. Para não alongar demais o post, deixo o trecho da documentação que explica isso &lt;a href="https://github.com/invariantlabs-ai/mcp-scan?tab=readme-ov-file#server-proxying" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resumo
&lt;/h3&gt;

&lt;p&gt;Com a chegada dos agentes e servidores MCP, surgem também novas ameaças. Ter uma ferramenta como o &lt;strong&gt;mcp-scan&lt;/strong&gt; ajuda bastante a manter o ambiente seguro. Mesmo ainda estando na versão v0, é um projeto promissor — e não é à toa que entrou no Tech Radar da Thoughtworks.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.thoughtworks.com/en-br/radar" rel="noopener noreferrer"&gt;Tech Radar Thoughtworks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/invariantlabs-ai/mcp-scan" rel="noopener noreferrer"&gt;mcp-scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks" rel="noopener noreferrer"&gt;MCP Tool Poisoning Attacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://context7.com/" rel="noopener noreferrer"&gt;Context7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/engineering/code-execution-with-mcp" rel="noopener noreferrer"&gt;Code execution with mcp - Anthropic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Como acompanhar a evolução da tecnologia sem se perder no caminho no mundo "2x"</title>
      <dc:creator>Caramelo da TI</dc:creator>
      <pubDate>Sun, 09 Nov 2025 15:19:34 +0000</pubDate>
      <link>https://dev.to/caramelo-ti/como-acompanhar-a-evolucao-da-tecnologia-sem-se-perder-no-caminho-no-mundo-2x-341p</link>
      <guid>https://dev.to/caramelo-ti/como-acompanhar-a-evolucao-da-tecnologia-sem-se-perder-no-caminho-no-mundo-2x-341p</guid>
      <description>&lt;p&gt;Nesse mundo em “2x”, estamos sempre correndo. É fácil se sentir atrasado e sobrecarregado com a enxurrada de novidades tecnológicas.&lt;br&gt;
E a &lt;strong&gt;IA&lt;/strong&gt; só acelera esse processo: primeiro vieram as LLMs, depois os agentes de IA, e quando menos esperamos, já estamos ouvindo falar de MCP Servers.&lt;/p&gt;

&lt;p&gt;Mas afinal, o quanto dessa montanha de novidades é realmente importante?&lt;br&gt;
O que é hype? E será que vale passar todo o tempo livre tentando acompanhar tudo?&lt;/p&gt;

&lt;p&gt;Durante minha trajetória na tecnologia, já me vi (e ainda me vejo) nesse dilema (&lt;a href="https://pt.wikipedia.org/wiki/S%C3%ADndrome_de_FOMO" rel="noopener noreferrer"&gt;FOMO&lt;/a&gt;).&lt;br&gt;
Neste texto, quero compartilhar &lt;strong&gt;como aprendi a lidar com isso e acompanhar o ritmo da tecnologia sem surtar.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A IA acelerando a evolução e o nosso jeito de aprender
&lt;/h2&gt;

&lt;p&gt;A cada semana surgem novas promessas: “a IA vai substituir pessoas”, “vai multiplicar a produtividade”… e, em parte, é verdade.&lt;br&gt;
Mas é importante se perguntar: &lt;strong&gt;até onde a IA deve fazer por você?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Com a velocidade que ela impõe, pode ser tentador “combater fogo com fogo”. Mas dessa forma quem está aprendendo? É você ou a IA?&lt;/p&gt;

&lt;p&gt;Durante o &lt;em&gt;Workshop do Instituto de Inteligência Artificial (LNCC, 2025)&lt;/em&gt; , &lt;a href="https://dexl.lncc.br/team/patrick-valduriez" rel="noopener noreferrer"&gt;Patrick Valduriez&lt;/a&gt; trouxe uma reflexão poderosa:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em que ponto a IA deixa de ser copiloto e passa a ser piloto?&lt;br&gt;
E o que isso muda na forma como aprendemos e decidimos?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A IA é uma aliada incrível, mas ainda é uma ferramenta e cabe a você usá-la com propósito.&lt;br&gt;
Durante os estudos, use-a &lt;strong&gt;para entender a solução&lt;/strong&gt;, não apenas &lt;strong&gt;para obter a solução&lt;/strong&gt;. Assim, &lt;strong&gt;você aprende de fato&lt;/strong&gt;, e não só “acerta”.&lt;/p&gt;

&lt;p&gt;Vale lembrar: as respostas de uma LLM são limitadas ao conhecimento com o qual foi treinada, e nem sempre estão corretas. Uma LLM não pensa, ela calcula a &lt;strong&gt;probabilidade&lt;/strong&gt; da próxima palavra (token) ser a que esperamos. Existe sempre uma zona escura, onde talvez nem saiba responder &lt;em&gt;(ainda)&lt;/em&gt;.&lt;br&gt;
E é aí que entra a verdadeira curiosidade humana.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que você domina, o que conhece e o que ainda não conhece
&lt;/h2&gt;

&lt;p&gt;Antes de mais nada, vale esclarecer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;O que você domina:&lt;/strong&gt; é o conhecimento que usa no dia a dia, fala sobre com segurança e aplica com naturalidade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O que você conhece, mas não domina:&lt;/strong&gt; sabe que existe, entende o conceito, mas não saberia aplicar de imediato.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O que você não conhece:&lt;/strong&gt; está fora da sua bolha, e justamente por não conhecer, não sabe que não sabe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa preocupação em “estar em dia” não é nova.&lt;br&gt;
Há alguns anos, levantei essa questão com meu amigo e mentor &lt;strong&gt;MSc. Augusto José Moreira da Fonseca&lt;/strong&gt;, e ele me disse algo que nunca esqueci:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Você não precisa aprender tudo. Mas conheça o máximo do que existe e para que serve, adicionando ao seu cinto de utilidades.&lt;br&gt;
Assim, quando o problema aparecer, você saberá que ferramenta usar e aí, sim, vai aprender a fundo.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Na prática
&lt;/h3&gt;

&lt;p&gt;Imagine que todo o conhecimento em tecnologia seja representado por um triângulo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbj2wfvwseumfuw4yqc56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbj2wfvwseumfuw4yqc56.png" alt="representação da distribuição do conhecimento na área de um triangulo" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A parte verde — pequena — é o que &lt;strong&gt;dominamos&lt;/strong&gt;.&lt;br&gt;
Ela cresce com tempo e prática, mas exige energia e constância. Se for algo que não usamos, esquecemos rapidamente.&lt;/p&gt;

&lt;p&gt;Por isso, a energia deve estar voltada a &lt;strong&gt;expandir a parte amarela&lt;/strong&gt;: o que &lt;strong&gt;conhecemos, mas ainda não dominamos&lt;/strong&gt;.&lt;br&gt;
Trazer luz ao desconhecido, entender para que serve e quando serve cada coisa, e assim montar o seu “cinto de utilidades”.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regra dos 30 minutos
&lt;/h3&gt;

&lt;p&gt;Separe 30 minutos por dia só para mapear o que está acontecendo:&lt;br&gt;
leia títulos de blogs (O’Reilly Radar, Azure Blog, AWS Blog, dev.to, etc.), veja vídeos de referência, siga repositórios do GitHub de tecnologias e empresas que você acompanha (Microsoft, Vercel, Meta…).&lt;/p&gt;

&lt;p&gt;Se algo chamar atenção, leia ou assista com foco nos &lt;strong&gt;porquês&lt;/strong&gt; e &lt;strong&gt;quandos&lt;/strong&gt;.&lt;br&gt;
Entenda o contexto e o problema que aquela tecnologia ou técnica resolve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Nesse momento, você filtra o que tem real aplicabilidade pra você.&lt;br&gt;
É legal entender como criar uma linguagem do zero, mas talvez não seja prioridade ou não tenha tanta aplicabilidade se você é um dev web júnior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Assim, você expande a parte “&lt;strong&gt;o que conhece, mas não domina&lt;/strong&gt;”, sem se perder no mar de novidades.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3juqkii48e1h6onx5vz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3juqkii48e1h6onx5vz.png" alt="representação da distribuição do conhecimento na área de um triangulo" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para quem acredita que '&lt;em&gt;santo de casa não faz milagres&lt;/em&gt;', Mark Richards, autor de Fundamentals of Software Architecture dentre outros, explica esse mesmo conceito de forma mais detalhada em sua série &lt;a href="https://www.developertoarchitect.com/lessons/lesson3.html" rel="noopener noreferrer"&gt;Developer to Architect — Lesson 3: Gaining Technical Breadth&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;É importante entender que essa estratégia não significa que não precisa se aprofundar em nenhum tópico. Mas sim que dessa forma, é possível dedicar tempo e energia de forma estratégica nos estudos e ciente do que existe, caso precise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Carta para iniciantes na área
&lt;/h2&gt;

&lt;p&gt;Quando comecei na tecnologia, me assustei com a quantidade de coisas novas, parecia impossível acompanhar.&lt;br&gt;
E adivinha? &lt;strong&gt;É impossível mesmo.&lt;/strong&gt; 😄&lt;/p&gt;

&lt;p&gt;Mas tudo bem. Você não precisa ser especialista em tudo.&lt;/p&gt;

&lt;p&gt;Uma das principais características do ser humano é a &lt;strong&gt;curiosidade&lt;/strong&gt; e a &lt;strong&gt;capacidade de aprender&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Assim como capacidades físicas, exige exercício para chegar a sua melhor performance.&lt;br&gt;
Se você faz musculação por exemplo, entende que precisa treinar frequentemente e também dar um tempo de descanso. Não é diferente com a nossa capacidade de aprender.&lt;/p&gt;

&lt;p&gt;Comece pelos fundamentos, eles quase nunca mudam.&lt;br&gt;
Os princípios da Orientação a Objetos, por exemplo, são praticamente os mesmos desde os anos 1960.&lt;br&gt;
Aprenda uma linguagem e framework, e já terá meio caminho andado para outras linguagens e frameworks. &lt;br&gt;
Logo perceberá que muito do conhecimento é &lt;strong&gt;transferível&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Eu comecei com &lt;code&gt;PHP&lt;/code&gt; e &lt;code&gt;jQuery&lt;/code&gt;.&lt;br&gt;
Meu primeiro trabalho foi com &lt;code&gt;Laravel&lt;/code&gt; e &lt;code&gt;Angular&lt;/code&gt;.&lt;br&gt;
Depois, migrei para &lt;code&gt;.NET&lt;/code&gt;, e percebi que os conceitos se repetem: &lt;code&gt;Eloquent&lt;/code&gt; no Laravel, &lt;code&gt;Entity Framework Core&lt;/code&gt; no .NET, &lt;code&gt;SQLAlchemy&lt;/code&gt; no Python, entre outras coisas.&lt;br&gt;
A ideia é a mesma, só muda a sintaxe e alguns detalhes.&lt;/p&gt;

&lt;p&gt;Utilize sim IA para estudar, mas use consciente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Se você é um desenvolvedor e pede para um agente criar para você a implementação de alguma funcionalidade, entenda, &lt;strong&gt;você ainda é responsável&lt;/strong&gt; pelo código gerado e tem a obrigação profissional de responder por ele. O mesmo se aplica a outros papéis. Entenda o que foi feito e o porquê.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como estudante autodidata, acaba caindo por sua própria responsabilidade a condução até o conhecimento, que antes seria responsabilidade de um mentor.&lt;/p&gt;

&lt;p&gt;Dê tempo para você processar a informação, descanse.&lt;br&gt;
Arquitetos, programadores, profissionais de tecnologia em geral exercem uma atividade intelectual. Não é quantidade de cliques ou tempo em frente de tela que define sua produtividade.&lt;/p&gt;

&lt;p&gt;Quem nunca teve aquela ideia que resolve o problema enquanto lava uma louça, faz uma atividade fora ou mesmo dormindo?!&lt;/p&gt;

&lt;p&gt;E talvez o conselho mais valioso: escreva, compartilhe, explique para alguém.&lt;br&gt;
Ao ensinar, você descobre novas dúvidas, e consolida o aprendizado de verdade.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.developertoarchitect.com/lessons/" rel="noopener noreferrer"&gt;Mark Richards - developertoarchitect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/augusto-jose-fonseca/" rel="noopener noreferrer"&gt;Augusto José Fonseca&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pt.wikipedia.org/wiki/S%C3%ADndrome_de_FOMO" rel="noopener noreferrer"&gt;Síndrome de FOMO(fear of missing out)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Obs: texto revisado por IA 🤖😁🦾&lt;/em&gt;&lt;/p&gt;

</description>
      <category>learning</category>
      <category>career</category>
      <category>newbie</category>
    </item>
    <item>
      <title>Gerenciamento Feature Flag em Azure Functions</title>
      <dc:creator>Caramelo da TI</dc:creator>
      <pubDate>Tue, 04 Nov 2025 19:17:58 +0000</pubDate>
      <link>https://dev.to/caramelo-ti/gerenciamento-feature-flag-em-azure-functions-1e5n</link>
      <guid>https://dev.to/caramelo-ti/gerenciamento-feature-flag-em-azure-functions-1e5n</guid>
      <description>&lt;h2&gt;
  
  
  O que é Feature Flag?
&lt;/h2&gt;

&lt;p&gt;Feature flag é uma técnica que permite habilitar ou desabilitar funcionalidades de forma dinâmica, sem a necessidade de alteração no código. Essencialmente, funciona como um "interruptor" (ou "toggle" ou "flag") que controla o comportamento de uma aplicação.&lt;/p&gt;

&lt;p&gt;O uso dessa técnica facilita a gestão de novas atualizações, impacto de dependência de publicação coordenada entre times, além de permitir estratégias de experimentação de novas funcionalidades ou otimizações.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Configurando o Microsoft.FeatureManagement em Azure Functions
&lt;/h2&gt;

&lt;p&gt;Dependendo do seu caso, pode ser que a velha variável de ambiente resolva ou alguma implementação customizada, contudo o pacote &lt;code&gt;Microsoft.FeatureManagement&lt;/code&gt; atende tanto o cenário mais simples, quanto um mais complexo, pois já tem built-in várias funcionalidades como estratégia de distribuição de variantes, tempo de disponibilidade de uma funcionalidade entre outros. E também vale ressaltar sua capacidade de customização, permitindo criar a sua regra de como e quando determinada &lt;code&gt;feature-flag&lt;/code&gt; deve estar habilitada ou não.&lt;/p&gt;

&lt;p&gt;Nesse exemplo estarei usando uma &lt;code&gt;Azure Function&lt;/code&gt; &lt;code&gt;in-process&lt;/code&gt; com &lt;code&gt;.Net 8&lt;/code&gt; para exemplificar a configuração e uso do pacote &lt;code&gt;Microsoft.FeatureManagement&lt;/code&gt; de forma prática. O fundamento aqui serve para outros modelos de aplicação .Net, mas o básico aqui dá para ter um pontapé inicial.&lt;/p&gt;

&lt;p&gt;O primeiro exemplo que encontramos na documentação é usando o recurso &lt;a href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/overview" rel="noopener noreferrer"&gt;App Configuration&lt;/a&gt; que centraliza o gerenciamento de configurações e feature flags da aplicação.&lt;br&gt;
Para isso é necessário criar o recurso, na primeira interação precisará atribuir o papel de &lt;code&gt;owner&lt;/code&gt; e então conseguirá editar e acessar as chaves de conexão.&lt;/p&gt;

&lt;p&gt;Feito isso é possível configurar a conexão na aplicação&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Caramelo.FoodDispenser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Azure.Functions.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration.AzureAppConfiguration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.FeatureManagement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;assembly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;FunctionsStartup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Startup&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Caramelo.FoodDispenser&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;Startup&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FunctionsStartup&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureAppConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IFunctionsConfigurationBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&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="n"&gt;ConfigurationBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAzureAppConfiguration&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;=&amp;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;connString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AZ_APP_CONFIG_CONN"&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="nf"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"_"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseFeatureFlags&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="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IFunctionsHostBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&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="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAzureAppConfiguration&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="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddFeatureManagement&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;blockquote&gt;
&lt;p&gt;💡 &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;O método .Select("_") é usado apenas para exemplificação — ele filtra todas as chaves começando com o prefixo _, o que na prática ignora as demais chaves do App Configuration.Mais detalhes sobre isso &lt;a href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-feature-flag-azure-functions-csharp?tabs=connection-string#connect-to-an-app-configuration-store" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Em produção, a variável de ambiente &lt;code&gt;AZ_APP_CONFIG_CONN&lt;/code&gt; deve ser configurada nos &lt;code&gt;Application Settings&lt;/code&gt; do Function App. Mais detalhe sobre isso &lt;a href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-feature-flag-azure-functions-csharp?tabs=connection-string#connect-to-an-app-configuration-store" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O exemplo usa Azure Functions in-process (.NET 8), mas a configuração é muito semelhante no modelo Isolated, mudando apenas a forma de injeção de dependências.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Na implementação vamos criar a function &lt;code&gt;Http Trigger&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Azure.WebJobs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Azure.WebJobs.Extensions.Http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Logging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.FeatureManagement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Caramelo.FoodDispenser&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;FeedDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IFeatureManagerSnapshot&lt;/span&gt; &lt;span class="n"&gt;featureManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FeedDog"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthorizationLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Anonymous&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Route&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"feed"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;log&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;requestBody&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StreamReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ReadToEndAsync&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="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FeedingRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;portions&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;featureManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsEnabledAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GreedyMode"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Greedy Mode activated 🥩 — doubling portion!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;portions&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="n"&gt;Portions&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;DispenseFood&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="n"&gt;DeviceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;portions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Normal Mode 🍖 — regular portion."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;portions&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="n"&gt;Portions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;DispenseFood&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="n"&gt;DeviceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;portions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;


        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OkObjectResult&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;FeedingResponse&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="n"&gt;DogName&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="n"&gt;DeviceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;portions&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DispenseFood&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;deviceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;portions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// lógica simulada&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;FeedingRequest&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;DogName&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;DeviceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Portions&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;record&lt;/span&gt; &lt;span class="nc"&gt;FeedingResponse&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;DogName&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;DeviceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Portions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O principal está na injeção de &lt;code&gt;IFeatureManagerSnapshot&lt;/code&gt; e seu uso em &lt;code&gt;await featureManager.IsEnabledAsync("GreedyMode")&lt;/code&gt;.&lt;br&gt;
Nesse trecho estamos verificando se a feature flag &lt;em&gt;GreedyMode&lt;/em&gt; está habilitada e aplicando o comportamento alternativo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 É possível usar o &lt;code&gt;IFeatureManager&lt;/code&gt; ao invés do &lt;code&gt;IFeatureManagerSnapshot&lt;/code&gt;, contudo o segundo faz com que as configurações de features flags sejam consistentes em tempo de requisição. Ou seja, mesmo que dois serviços injetem a classe e ela troque de valor em tempo de requisição, será sempre considerado o valor inicial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mas para que funcione conforme esperado, antes é necessário cadastrar essa feature flag.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cadastrando uma feature flag no App Configuration
&lt;/h3&gt;

&lt;p&gt;De volta ao Portal Azure, acessando o recurso &lt;code&gt;App Configuration&lt;/code&gt; é possível encontrar a opção &lt;code&gt;Feature manager&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlgd47pz476539dkpw7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlgd47pz476539dkpw7p.png" alt="opção Feature manager" width="482" height="942"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicando nela, na parte superior existe um botão &lt;code&gt;Criar&lt;/code&gt; que ao clicar apresenta duas opções &lt;code&gt;Feature Flag&lt;/code&gt; e &lt;code&gt;Variant Feature Flag&lt;/code&gt;. Sem entrar muito em detalhes, ambas são muito parecidas, mas a segunda permite que tenha mais estados que &lt;code&gt;On&lt;/code&gt; e &lt;code&gt;Off&lt;/code&gt;, adicionando mais variações. Vamos focar na primeira mesmo nesse exemplo.&lt;/p&gt;

&lt;p&gt;Na tela de criação é possível adicionar algumas descrições para facilitar a identificação do motivo da feature flag e efeito na aplicação, mas o importante para a aplicação é o atributo &lt;code&gt;Key&lt;/code&gt;.&lt;br&gt;
O nome da &lt;code&gt;Key&lt;/code&gt; deve corresponder exatamente ao valor usado em &lt;code&gt;IsEnabledAsync()&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🐞 Não recebi nenhum erro ao criar com uma Key com nome composto separado por espaço, mas pode gerar confusão, então recomendo escolher sua convenção favorita e adotar ela. &lt;strong&gt;Atenção também com espaços no final da Key&lt;/strong&gt; &lt;em&gt;(Sim eu sofri com isso)&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yfiflowkgee48om7xad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yfiflowkgee48om7xad.png" alt="Tela de criação" width="800" height="815"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Filtros
&lt;/h4&gt;

&lt;p&gt;Ainda na tela de criação existe a opção de adicionar filtros, caso marque o checkbox e clique no botão &lt;code&gt;Criar&lt;/code&gt; irá ser exibido o menu para configuração do filtro.&lt;/p&gt;

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

&lt;p&gt;A funcionalidade já possui 2 tipos de filtros built-in, &lt;code&gt;Time window&lt;/code&gt; e &lt;code&gt;Targeting&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time window: permite que a feature flag, se habilitada, só tenha efeito durante uma janela de tempo configurada.&lt;/li&gt;
&lt;li&gt;Targeting: permite que a feature flag, se habilitada, só tenha efeito para usuários ou grupos especificados.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Existem outros tipos de filtro built-in não disponíveis por padrão na interface do &lt;code&gt;App Configuration&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Também é possível criar o seu próprio filtro, de forma com que a aplicação saiba interpretar e aplicar o comportamento esperado.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Para esse exemplo não será aplicado nenhum filtro&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Habilitando e desabilitando uma feature flag
&lt;/h3&gt;

&lt;p&gt;Criada a feature flag é possível observar o resultado da operação conforme configurado no &lt;code&gt;App Configuration&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Greedy Mode activated 🥩 — doubling portion!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Desabilitando:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2998oi9pd9n26jzs9ex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2998oi9pd9n26jzs9ex.png" alt="Feat disabled" width="800" height="126"&gt;&lt;/a&gt;&lt;br&gt;
temos a seguinte saída:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Normal Mode 🍖 — regular portion.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Embora o exemplo seja simples, o fundamento se aplica em outros cenários mais complexos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternativas ao App Configuration
&lt;/h2&gt;

&lt;p&gt;As configurações de feature flags podem ser por &lt;code&gt;App Configuration&lt;/code&gt;, mas também podem ser configuradas no &lt;code&gt;local.settings.json&lt;/code&gt;,&lt;code&gt;appsettings.json&lt;/code&gt; ou a partir de outra origem customizada.&lt;/p&gt;

&lt;p&gt;A configuração do &lt;code&gt;Microsoft.FeatureManagement&lt;/code&gt; é a partir da interface &lt;code&gt;IConfiguration&lt;/code&gt;, o que faz com que seja fácil prover conforme sua aplicação já o faz.&lt;/p&gt;

&lt;p&gt;Internamente o pacote irá tentar resolver as feature flags procurando nas configurações as chaves conforme a seguinte representação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"feature_management"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"feature_flags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FeatureA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FeatureB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/microsoft/FeatureManagement-Dotnet/blob/main/schemas/FeatureManagement.Dotnet.v1.0.0.schema.json" rel="noopener noreferrer"&gt;FeatureManagement.Dotnet.v1.0.0.schema.json&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Contudo também é possível indicar qual a &lt;code&gt;Section&lt;/code&gt; customizada você configurou:&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;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddFeatureManagement&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="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CarameloFeaturesFlags"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  local.settings.json
&lt;/h3&gt;

&lt;p&gt;Caso use o &lt;code&gt;local.settings.json&lt;/code&gt; vale lembrar que &lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings#app-setting-considerations" rel="noopener noreferrer"&gt;os delimitadores hierárquicos são &lt;code&gt;__&lt;/code&gt; ou &lt;code&gt;::&lt;/code&gt;&lt;/a&gt;, por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"feature_management::feature_flags:0:id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FeatureA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"feature_management::feature_flags:0:enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"feature_management::feature_flags:1:id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FeatureB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"feature_management::feature_flags:1:enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Alternativa customizada
&lt;/h3&gt;

&lt;p&gt;Particularmente não gosto do padrão de delimitadores de Azure Functions, mas isso por si só não seria motivo de aumentar a complexidade.&lt;br&gt;
Contudo caso precise integrar as flags com um CMS interno, banco ou painel próprio e o &lt;code&gt;App Configuration&lt;/code&gt; não seja uma opção, é possível customizar um outro provedor das features flags.&lt;br&gt;
Mas falar é fácil, vamos ao código.&lt;/p&gt;

&lt;p&gt;Para prover uma opção customizada deve-se implementar a interface &lt;code&gt;IFeatureDefinitionProvider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Essa interface obriga implementar 2 métodos, &lt;code&gt;GetAllFeatureDefinitionsAsync()&lt;/code&gt; que retorna todas as features flags configuradas e &lt;code&gt;GetFeatureDefinitionAsync(string featureName)&lt;/code&gt; que obtém uma feature flag pelo seu nome.&lt;/p&gt;

&lt;p&gt;Uma abordagem mais interessante para obter o mesmo dinamismo que o &lt;code&gt;App Configuration&lt;/code&gt; possui, seria implementar utilizando algum recurso de armazenamento como banco de dados, dessa forma é possível alterar os valores em necessidade de alterar a aplicação ou uma nova publicação, mas para fins de exemplificação é possível implementar utilizando um arquivo json para a configuração.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"featureFlags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FeatureA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FeatureB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E implementando a interface &lt;code&gt;IFeatureDefinitionProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.FeatureManagement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Caramelo.FoodDispenser&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;JsonFileFeatureFlagDefinitionProvider&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;appRootPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFeatureDefinitionProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;FeatureFlagFileName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"feature-flags.json"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FeatureDefinition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetFeatureDefinitionAsync&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;featureName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;featureDefinition&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;GetAllFeatureDefinitionsAsync&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;featureDefinition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;featureName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;featureDefinition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;IAsyncEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FeatureDefinition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllFeatureDefinitionsAsync&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;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appRootPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FeatureFlagFileName&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;featureFlagsJson&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;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllTextAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;featureManagementConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FeatureManagementConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;featureFlagsJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;featureFlag&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;featureManagementConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FeatureFlags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FeatureDefinition&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;featureFlag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;EnabledFor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;featureFlag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enabled&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"AlwaysOn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;FeatureManagementConfig&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;FeatureFlag&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;FeatureFlags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;FeatureFlag&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;Enabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;    
    &lt;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;
  
  
  Manutenção e escalabilidade
&lt;/h2&gt;

&lt;p&gt;O uso de feature flags é uma abordagem que pode facilitar o gerenciamento de versões de sua aplicação, mas também um aliado a experimentação e mitigação de risco. &lt;/p&gt;

&lt;p&gt;É possível reduzir o risco de uma publicação de nova versão aplicando a técnica &lt;a href="https://martinfowler.com/bliki/CanaryRelease.html" rel="noopener noreferrer"&gt;Canary Release&lt;/a&gt;, realizar experimentos a fim de obter insights e dados coletados através de &lt;a href="https://www.salesforce.com/br/blog/teste-ab/" rel="noopener noreferrer"&gt;Teste A/B&lt;/a&gt; e também ter uma rápida resposta caso alguma coisa não esteja funcionando como esperado (Graceful Degradation).&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;Microsoft.FeatureManagement&lt;/code&gt; facilita as abordagem citadas já com seus &lt;a href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/feature-management-dotnet-reference#built-in-feature-filters" rel="noopener noreferrer"&gt;filtros built-in&lt;/a&gt;(&lt;code&gt;PercentageFilter&lt;/code&gt;, &lt;code&gt;TimeWindowFilter&lt;/code&gt;, &lt;code&gt;TargetingFilter&lt;/code&gt;). Vale a pena dar uma conferida também na documentação o quanto é possível customizar os filtros. Ainda usando o &lt;code&gt;App configuration&lt;/code&gt; ao editar uma regra, existe a opção &lt;code&gt;Advanced Edit&lt;/code&gt; que permite customizar ainda mais os filtros já existentes. As mesmas customizações são possíveis de fazer usando outro método de configuração das features flags.&lt;br&gt;
Tudo isso permite lançar features de forma incremental e controlada, reduzindo riscos de publicação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deixando o código mais elegante:
&lt;/h2&gt;

&lt;p&gt;Um ponto que particularmente me incomoda é precisar aplicar uma condicional para a feature flag, interrompendo do encadeamento de ideias ao analisar um código. Contudo para aplicações mais simples, essa estratégia se prova suficiente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A simplicidade é o último grau de sofisticação - atribuída a Leonardo Da Vinci&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mas, conforme a aplicação cresce, pode ser necessário adotar estratégias mais sofisticadas para desacoplar a lógica de decisão da lógica de negócio, conforme abordado por Pete Hodgson no artigo&lt;br&gt;
&lt;a href="https://martinfowler.com/articles/feature-toggles.html#ImplementationTechniques" rel="noopener noreferrer"&gt;Feature Toggles&lt;/a&gt;, onde apresenta estratégias para desacoplar os pontos de tomada de decisão dos de lógica, levando em consideração a gestão das features flags com o crescimento saudável da aplicação.&lt;br&gt;
Não vou abordar esse tema, mas cabe a você avaliar o impacto e crescimento e complexidade da aplicação, para decidir se vale ou não aplicar alguma técnica para melhorar a manutenção das features flags.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/microsoft/FeatureManagement-Dotnet" rel="noopener noreferrer"&gt;Microsoft.FeatureManagement on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-feature-flag-azure-functions-csharp?tabs=connection-string#connect-to-an-app-configuration-store" rel="noopener noreferrer"&gt;Quickstart: Add feature flags to an Azure Functions app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/feature-management-dotnet-reference" rel="noopener noreferrer"&gt;.NET feature management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/overview" rel="noopener noreferrer"&gt;What is Azure App Configuration?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/articles/feature-toggles.html#ImplementationTechniques" rel="noopener noreferrer"&gt;feature toggles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azurefunctions</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>azure</category>
    </item>
    <item>
      <title>Should I wait or should I go?! Quando usar .ConfigureAwait() em Tasks .Net?</title>
      <dc:creator>Caramelo da TI</dc:creator>
      <pubDate>Mon, 03 Nov 2025 17:46:56 +0000</pubDate>
      <link>https://dev.to/caramelo-ti/should-i-wait-or-should-i-go-quando-usar-configureawait-em-tasks-net-5k2</link>
      <guid>https://dev.to/caramelo-ti/should-i-wait-or-should-i-go-quando-usar-configureawait-em-tasks-net-5k2</guid>
      <description>&lt;h2&gt;
  
  
  Para que serve?
&lt;/h2&gt;

&lt;p&gt;Antes de falar do tópico principal, vamos falar do famigerado tipo &lt;code&gt;Task&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Task-based asynchronous pattern e o tipo Task
&lt;/h3&gt;

&lt;p&gt;A Task surgiu junto do &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap" rel="noopener noreferrer"&gt;Task-based asynchronous pattern (TAP)&lt;/a&gt;&lt;br&gt;
, que simplifica a representação da inicialização e conclusão de uma operação assíncrona.&lt;br&gt;
O TAP foi incluído no .NET Framework 4 e desde então é a forma recomendada de lidar com programação assíncrona e introduziu o namespace &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks?view=net-9.0" rel="noopener noreferrer"&gt;System.Threading.Tasks&lt;/a&gt;&lt;br&gt;
 e, com ele, o tipo &lt;code&gt;Task&lt;/code&gt;, cuja finalidade é representar uma operação assíncrona.&lt;/p&gt;

&lt;p&gt;Uma &lt;code&gt;Task&lt;/code&gt; representa uma operação que eventualmente produzirá um resultado, poderá falhar (lançar exceção) ou ser cancelada.&lt;br&gt;
Ela é essencialmente um contêiner que descreve o andamento e o estado da operação assíncrona.&lt;/p&gt;
&lt;h2&gt;
  
  
  O que vem depois do &lt;code&gt;await&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Uma vez invocado um método que gera uma operação assíncrona, essa operação será executada de forma independente, e podemos usar o operador &lt;code&gt;await&lt;/code&gt; para suspender a execução até que o resultado esteja disponível.&lt;/p&gt;

&lt;p&gt;Vamos considerar o 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="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;GetData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="k"&gt;params&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;validParams&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;params&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;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;UpdateUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código acima, o compilador divide o método em duas partes: antes e depois do &lt;code&gt;await&lt;/code&gt;.&lt;br&gt;
Antes do &lt;code&gt;await&lt;/code&gt; temos a parte síncrona, e depois do await temos a continuação (&lt;em&gt;continuation&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Essa continuação pode ou não ser executada em outra thread, depende do contexto e do estado da &lt;code&gt;Task&lt;/code&gt;.&lt;br&gt;
Se a &lt;code&gt;Task&lt;/code&gt; já estiver concluída, a continuação pode ocorrer na mesma thread; se não, pode ocorrer em uma thread diferente.&lt;/p&gt;

&lt;p&gt;Durante a geração desse código, o compilador captura o contexto atual, que pode ser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um UI Context (WPF, WinForms),&lt;/li&gt;
&lt;li&gt;Um ASP.NET request context (ASP.NET clássico),&lt;/li&gt;
&lt;li&gt;Ou simplesmente nenhum contexto, como em ASP.NET Core ou Console Apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse contexto é representado pelo objeto &lt;code&gt;SynchronizationContext&lt;/code&gt;.&lt;br&gt;
De forma simplificada, ele é responsável por orquestrar a execução assíncrona e decidir em qual thread a continuação do &lt;code&gt;await&lt;/code&gt; será executada.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ok, e o &lt;code&gt;.ConfigureAwait()&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;É aqui que entra o nosso amigo &lt;code&gt;ConfigureAwait(bool)&lt;/code&gt;.&lt;br&gt;
Esse método recebe um parâmetro booleano chamado &lt;code&gt;continueOnCapturedContext&lt;/code&gt;, e indica se o código após o &lt;code&gt;await&lt;/code&gt; deve ou não voltar ao contexto original capturado.&lt;/p&gt;

&lt;p&gt;true (padrão): a continuação é executada de volta ao contexto original (por exemplo, a thread da UI).&lt;/p&gt;

&lt;p&gt;false: a continuação é executada em qualquer thread disponível do ThreadPool, sem retornar ao contexto original.&lt;/p&gt;

&lt;p&gt;Por padrão, o valor é true, ou seja, todo código após o &lt;code&gt;await&lt;/code&gt; tenta continuar no mesmo contexto em que a Task foi chamada.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;.ConfigureAwait(false)&lt;/code&gt; sempre então! Certo?!
&lt;/h3&gt;

&lt;p&gt;Você pode estar pensando:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Se eu não importo que meu código seja continuado em outra thread, posso poupar o &lt;code&gt;SynchronizationContext&lt;/code&gt; do trabalho e ganhar performance, não bloqueando a thread principal. Então vou usar &lt;code&gt;.ConfigureAwait(false)&lt;/code&gt; sempre!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essa é uma conclusão comum, e equivocada.&lt;br&gt;
De fato, muita gente passou a usar &lt;code&gt;.ConfigureAwait(false)&lt;/code&gt; em todo lugar após ler recomendações como as de Stephen Cleary em &lt;a href="https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#configure-context" rel="noopener noreferrer"&gt;Async/Await Best Practices&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futlm6jis8oxb2z4dogyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futlm6jis8oxb2z4dogyh.png" alt="Screenshoot of Async/Await Best Pratices" width="800" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No entanto, o uso indiscriminado pode causar &lt;strong&gt;bugs difíceis de rastrear&lt;/strong&gt;, especialmente quando diferentes pessoas mantêm o código sem entender o motivo do uso.&lt;/p&gt;

&lt;p&gt;Em muitos casos, remover um &lt;code&gt;.ConfigureAwait(false&lt;/code&gt;) antigo resolve um bug misterioso, o tipo de problema “isso estava aqui desde 2010 ninguém entende o porquê”.&lt;/p&gt;

&lt;p&gt;Além disso, não há ganho de performance perceptível ao usar &lt;code&gt;false&lt;/code&gt;; o benefício está em evitar dependência do contexto (por exemplo, para evitar deadlocks em bibliotecas reutilizáveis).&lt;/p&gt;
&lt;h3&gt;
  
  
  O que pode dar errado?
&lt;/h3&gt;

&lt;p&gt;Vamos supor que temos o código inicial, que roda em uma aplicação WinForms ou WPF, mas agora adicionamos o &lt;code&gt;.ConfigureAwait(false)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;GetData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="k"&gt;params&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;validParams&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;params&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;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validParams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;UpdateUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, o UpdateUI(data) será executado em uma thread diferente da principal.&lt;br&gt;
Como apenas a thread da UI pode atualizar elementos visuais, isso resultará na seguinte exceção:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ou seja, .ConfigureAwait(false) foi usado de forma incorreta.&lt;br&gt;
O próprio Stephen Cleary destacou isso em uma resposta no &lt;a href="https://stackoverflow.com/questions/62500130/why-is-writing-configureawaitfalse-on-every-line-with-await-always-recommended/62505101#comment110575296_62505101" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mesmo fora de aplicações gráficas, &lt;code&gt;.ConfigureAwait(true)&lt;/code&gt; pode causar deadlocks, especialmente no ASP.NET Framework clássico, onde cada requisição possui seu próprio SynchronizationContext.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RandomLibraryService&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetDataAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ⚠️ Usa o contexto original (continueOnCapturedContext = true)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ASP.NET Framework, não Core&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;HomeController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;RandomLibraryService&lt;/span&gt; &lt;span class="n"&gt;_rls&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ⚠️ Chamando async de forma síncrona&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_rls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDataAsync&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui, a requisição HTTP é associada a um &lt;code&gt;AspNetSynchronizationContext&lt;/code&gt;.&lt;br&gt;
Quando &lt;code&gt;Index()&lt;/code&gt; chama &lt;code&gt;GetDataAsync().Result&lt;/code&gt;, a thread da requisição é bloqueada.&lt;br&gt;
O método &lt;code&gt;GetDataAsync()&lt;/code&gt; libera a thread e registra a continuação para o mesmo contexto capturado, que está bloqueado, gerando um deadlock.&lt;/p&gt;

&lt;p&gt;Mesmo fora de ambientes de UI, isso ocorre porque o código tenta retornar ao contexto original, que está indisponível.&lt;/p&gt;

&lt;p&gt;Em ambientes modernos como ASP.NET Core, isso não acontece, pois o &lt;code&gt;SynchronizationContext&lt;/code&gt; foi removido.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quando usar &lt;code&gt;.ConfigureAwait(false)&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;✅ Em bibliotecas e pacotes reutilizáveis, pois você não controla o contexto do chamador.&lt;br&gt;
Isso evita depender de um &lt;code&gt;SynchronizationContext&lt;/code&gt; desconhecido.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚠️ Em código de aplicação, normalmente não há necessidade de usá-lo.&lt;br&gt;
O comportamento padrão (true) é mais previsível e seguro.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stephen Toub (Microsoft) reforça isso no &lt;a href="https://devblogs.microsoft.com/dotnet/configureawait-faq/" rel="noopener noreferrer"&gt;ConfigureAwait FAQ&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If you’re writing app-level code, do not use ConfigureAwait(false).”&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Quando &lt;code&gt;await&lt;/code&gt; espera uma &lt;code&gt;Task&lt;/code&gt;, o comportamento padrão é capturar um contexto, que pode ser um &lt;code&gt;SynchronizationContext&lt;/code&gt;, ou na ausência dele, o &lt;code&gt;TaskScheduler.Current&lt;/code&gt;.&lt;br&gt;
Quando a &lt;code&gt;Task&lt;/code&gt; termina, o código após o await é executado nesse contexto capturado (&lt;code&gt;.ConfigureAwait(continueOnCapturedContext: true)&lt;/code&gt; é o comportamento padrão).&lt;/p&gt;

&lt;p&gt;Usar &lt;code&gt;.ConfigureAwait(false)&lt;/code&gt; instrui o runtime a não retornar ao contexto capturado, permitindo que o código continue em qualquer thread disponível do thread pool.&lt;/p&gt;

&lt;p&gt;Isso não significa que o código após o &lt;code&gt;await&lt;/code&gt; sempre rodará em outra thread, isso só acontece se o &lt;code&gt;await&lt;/code&gt; realmente suspender a execução (ou seja, se a Task ainda não estiver concluída).&lt;/p&gt;

&lt;p&gt;A dica final é, se não está desenvolvendo um pacote de uso geral, ou lidando com uma implementação customizada de &lt;code&gt;SynchronizationContext&lt;/code&gt;, muito provável que não precise usar &lt;code&gt;.ConfigureAwait()&lt;/code&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#configure-context" rel="noopener noreferrer"&gt;Async/Await - Best Practices in Asynchronous Programming (2013)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html" rel="noopener noreferrer"&gt;ASP.NET Core SynchronizationContext&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/configureawait-faq/" rel="noopener noreferrer"&gt;ConfigureAwait FAQ (2019)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/62500130/why-is-writing-configureawaitfalse-on-every-line-with-await-always-recommended/62505101#comment110575296_62505101" rel="noopener noreferrer"&gt;Pergunta do StackOverflow respondida pelo Stephen Cleary (2020)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/how-async-await-really-works/" rel="noopener noreferrer"&gt;How Async/Await Really Works in C# (2023)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html" rel="noopener noreferrer"&gt;.ConfigureAwait() in .NET 8 (2023)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/pulse/should-i-use-configureawaittrue-configureawaitfalse-viswanathan/" rel="noopener noreferrer"&gt;LinkedIn Post: Should I Use ConfigureAwait true or false&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>programming</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
