<?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: Victor de Oliveira Marinho</title>
    <description>The latest articles on DEV Community by Victor de Oliveira Marinho (@v1t4o).</description>
    <link>https://dev.to/v1t4o</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%2F529843%2F84f8a8dc-5482-4a43-8074-8c6af26c07f9.jpg</url>
      <title>DEV Community: Victor de Oliveira Marinho</title>
      <link>https://dev.to/v1t4o</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/v1t4o"/>
    <language>en</language>
    <item>
      <title>[dependêncIA] como (não) usar ferramentas de inteligência artificial de modo (in)produtivo para dev</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Mon, 21 Jul 2025 14:53:24 +0000</pubDate>
      <link>https://dev.to/v1t4o/dependencia-como-nao-usar-ferramentas-de-inteligencia-artificial-de-modo-inprodutivo-para-dev-2i6k</link>
      <guid>https://dev.to/v1t4o/dependencia-como-nao-usar-ferramentas-de-inteligencia-artificial-de-modo-inprodutivo-para-dev-2i6k</guid>
      <description>&lt;p&gt;Fala minha tropa, hoje venho trazer um tema aqui que tenho já matutado a um bom tempo, e acredito que agora eu tenho o mínimo de maturidade para poder falar sobre (embora ache que isso é só o começo de uma série, já que a IA veio pra ficar).&lt;/p&gt;

&lt;p&gt;O gatilho desse texto foi um &lt;a href="https://www.linkedin.com/posts/activity-7352012269125328896-LaAg?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAADcWAWIBPstxhRx0iZ0bKebm3CWZBDpIIfc" rel="noopener noreferrer"&gt;post&lt;/a&gt; do Leandro Proença (que também lançou um post no Bluesky), e a partir dos breve comentários, achei que seria massa trazer isso de uma forma mais corrida (acredito que em breve saia o artigo dele também sobre isso).&lt;/p&gt;

&lt;p&gt;Para começar, antes que os defensores de vibe coding venham tacar preda, eu trago nesse texto a minha experiência com inteligência artificial, e também de como eu acredito que ela pode ser benéfica. Já fui um cara mais contra ela, mas na engrenagem do capitalismo, eu não faço as regras, eu só aceito. Pois bem, vamos lá.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eu, Robô
&lt;/h2&gt;

&lt;p&gt;Bom, eu estive envolvido em dois momentos com projetos de IA de forma profissional, e acredito que isso me possibilitou ver dois momentos distintos o quanto ela avançou para o usuário final. Em 2023 a 2024 (se não me falha a memória), eu estive em um projeto pensando Chatbots com IA para auxiliar uma área que era muito onerada pelos contatos via aplicativo de comunicação interna. A ideia era utilizar alguma ferramenta que ajudasse a fazer uma triagem e resolver pequenas dúvidas. Tive contato nesse período com as ferramentas do Chatbase (que usa o GPT por baixo dos panos), e também do Gemini e Amazon Q (esses tive só apresentação de consultorias, sem ter um uso efetivo).&lt;/p&gt;

&lt;p&gt;No segundo momento, foi quando passaram a avaliar ferramentas de código com IA embutida. Por conta de me envolver em bastante projeto, acabei tendo a oportunidade de participar desse piloto junto com outros devs, e aqui foi onde eu acho que começou a ter coisas com as quais eu não concordava, não via que agregava valor e que não entregava resultado, segundo meu ponto de vista.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minority Report
&lt;/h2&gt;

&lt;p&gt;Pois bem, esse segundo momento foi um processo mais impositivo, mas acredito que era para justamente testar os limites da ferramenta e saber onde ela atenderia ou não. A ferramenta escolhida foi o Cursor, e a primeira vista não dei muita bola, até começar a perceber que havia uma pressão maior para usar a ferramenta diariamente (e era válido, aliás, quem estava encabeçando o projeto precisava de dados para tomar uma descisão). Decidi me abrir para a ferramenta, e comecei de forma tímida a utilizar o Chat, muito para geração de ARDs e PRDs das aplicações legadas, e me pareceu muito interessante nesse sentido.&lt;/p&gt;

&lt;p&gt;Depois avancei para uso do autocomplete e, enfim, comecei a ter uma fluidez maior. Contudo, sempre com um pé atrás - aliás, sou de humanas, essa criticidade de tudo faz parte de mim. Passado um tempo, a ferramenta se afirmou como útil, mas ao meu ver de forma muito prematura. Acredito que um tempo maior de benchmark faria mais sentido, além de qualificar os dados: quem estava usando a ferramenta (por níveis de Jr, Pl, Sr…), como estava usando, quando estava usando, para quê estava usando, qual a qualidade de prompt utilizada e, sobretudo, quantos prompts foram utilizados. Digo isso, pois um dos vídeos que vi na época foi do &lt;a href="https://www.youtube.com/watch?v=7TYbSf0pTpA" rel="noopener noreferrer"&gt;Augusto Galego&lt;/a&gt; sobre esse medo dos devs, e ele trazia esse ponto da relação entre quantidade de prompts e o quanto gastaria pra fazer na unha.&lt;/p&gt;

&lt;p&gt;Nesse processo, foi solicitado alguns feedbacks, e acredito que muitos mascaravam um limite, que é claro, dessas IAs que auxiliam na codificação, fora a elaboração de estatística sem ter um cuidado com o que se diz. Ninguém é bobo, todos nós somos adultos e vivemos em um mundo capitalista; no mundo do trabalho, somos divididos por níveis, e cada um toca a banda como deve tocar. Digo isso pois, você fornecer dados como: reduziu X%, aumentou X%, etc, etc, etc, é o que faz brilhar os olhos dos cabeça branca (quem tem dim dim de verdade). Essas métricas, segundo o breve curso que fiz de UX, condiziam mais com as famosas “métricas da vaidade”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Projeto Gemini
&lt;/h2&gt;

&lt;p&gt;Bão, chegamos ao ponto que eu queria chegar. Antes de qualquer coisa, acima eu só expûs o que eu senti e acreditava para aquele momento, inclusive em conversas que tive no privado com colegas e em reuniões conjuntas. Não se trata de nada além de perceber o óbvio em nossas relações de trabalho, como empregador e empregado.&lt;/p&gt;

&lt;p&gt;Indo pro que interessa. Estive em um projeto posterior para servir de case para a área, onde deveria utilizar IA de ponta-a-ponta - a ideia é interessante, se você agora pretende fazer um benchmark agressivo para saber os limites internos de onde a IA pode ir de fato. A princípio, era um sistema legado, que tínhamos já alguns problemas, e miramos nele por conta de uma simplicidade de lógica de negócio.&lt;/p&gt;

&lt;p&gt;Não vou trazer aqui o passo-a-passo desse projeto, pois trata-se de algo mais interno, e inclusive foi gerado apresentação para contar um pouco de como foi o processo (mas, claro, seguindo o rito corporativo). O que eu queria trazer aqui são os efeitos de como conduzi esse processo (claro, influenciado por uma necessidade de que eu não intervisse no código).&lt;/p&gt;

&lt;p&gt;Já havia cerca de 1 mês que estava usando o Cursor para pequenas coisas, e seguia o rito normal de trabalho (como os Incas e os Astecas). Até que chegou esse projeto, e a lei era: não deve haver intervenção do DEV. Ou seja, eu iria apenas guiar a IA a construir tudo de ponta-a-ponta, testar, enviar bugs do terminal para a IA, e ela se resolver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ex_Machina
&lt;/h2&gt;

&lt;p&gt;Esse período de duas semanas, eu tive um uso intenso de IA no dia-a-dia, basicamente o dia inteiro eu estava ali conversando com o Chat, usando o Claude Sonnet 4, e refazendo do zero o sistema legado escolhido. Quando foi gerado a primeira versão okayzinha, eu achei animal. E com isso fui ajustando layouts, resolvendos bugs, montando as funcionalidades - parecia coisa de outro mundo. Entretanto, cada vez mais notava um distanciamento meu em relação ao código. Em empresas de tecnologia se discute muito o ownership do produto que você trabalha, mas com essas IAs agora, como fica a questão?&lt;/p&gt;

&lt;p&gt;Nesse período, também me aperfeiçoei um pouco em prompts, usava Gemini como auxiliar para gerar prompts para o Cursor, mas não programei uma linha de código sequer, absolutamente nada. Apenas validava as construções, se elas faziam sentido, pedia para refatorar de maneira X, mas sem programar.&lt;/p&gt;

&lt;p&gt;Teve alguns momentos que me assustei pela facilidade: implementar em 15 minutos a tokenização de URLs para mascaramento de IDs, com testes já incluídos nos specs. Agora você me pergunta se eu sabia fazer isso na unha, vou ter que te falar que não.&lt;/p&gt;

&lt;p&gt;É onde percebi o quanto de produtividade que ela trazia, era o quanto de burrice ía crescendo em mim. Sem perceber no avanço, de mais duas semanas, em 1 mês eu posso atestar que tenho uma queda relativa cognitiva no que diz respeito ao uso de IA (servi de experimento pelo menos). Incomodado com isso, calhou que uma Newsletter do Tem vaga pra Jr! enviou esse texto aqui:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.hardware.com.br/noticias/uso-ia-chatgpt-prejudica-criatividade/?utm_source=substack&amp;amp;utm_medium=email" rel="noopener noreferrer"&gt;&lt;strong&gt;O preço invisível do ChatGPT: estudo revela que uso constante pode reduzir sua criatividade&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esse artigo fala um pouco de como o uso intensivo das IAs podem afetar as nossas ativações neurais, e de como a longo prazo isso representa um perigo. Chegou ao ponto, de eu começar a internalizar que não sabia mais programar, que eu era uma farsa. E, de fato, todo aquele monte de código não era meu, não fui eu que pensei, encadeei, nada disso. E se der problema em produção? Entraremos na Engenharia Reversa para descobrir o problema e no que vai dar. Ou capaz, que entraremos na era do “vibe fix”, reúne um monte de log, dados, joga pra IA e deixa ela resolver (será que dará certo para contextos que tem inúmeras integrações e complexidade lógica?).&lt;/p&gt;

&lt;p&gt;Fora isso, um tema pouco falado, todo mundo fala que você tem que aprender prompt, xyz, mas pouca gente fala do impacto em saúde mental que uso intensivo pode e deve estar gerando em desenvolvedores pelo mundo a fora. Essa pressão, cada vez maior, por resultados a todo custo, faz com que os devs abram mão de sua persona envolvida, para delegar para a IA, porque de fato ela entrega mais rápido, a questão é: entrega com qualidade?&lt;/p&gt;

&lt;p&gt;Com o Cursor, e outras ferramentas de código, criou-se um frenesi da entrega a qualquer custo, lideranças levando que o time aumentou em mais de 150%, é um novo ápice do capitalismo no ramo da tecnologia. E juntamente disso, vemos o ápice da alienação do trabalhador - é, a gente só sente quando a água bate na bunda. Quando os maquinários chegaram nas linhas de produção, quem estava no âmbito administrativo não sentiu que seria substituído, até que surgiu o computador, planilhas, sistemas (e todo esse mercado criou o mercado de devs). Mas agora, a conta tá chegando pra gente que somos peões premium. Como lidar com tudo isso?&lt;/p&gt;

&lt;h2&gt;
  
  
  Matrix
&lt;/h2&gt;

&lt;p&gt;Parabéns guerreiros e guerreiras, se tu chegou até aqui, depois de eu falar para um caralho, você só precisa clicar no link abaixo e mandar “EU QUERO” no comentário, que irei mandar os melhores prompts para salvar a sua vida, além de assinar minha newsletter semanal, e minha mentoria pela bagatela de 15 mil dól…..brinks.&lt;/p&gt;

&lt;p&gt;Bom, diante disso, “o que eu faço Victor? não uso IA? uso IA?”. Bão, aqui é aquele momento do Morpheus com o Neo, você tem duas escolhas:&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%2Fomyp1m5wx0h9zc0v5xqv.webp" 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%2Fomyp1m5wx0h9zc0v5xqv.webp" alt="Frame do filme Matrix" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1 - Usar a IA como ferramenta&lt;/p&gt;

&lt;p&gt;2 - Tornar-se gerente de IA&lt;/p&gt;

&lt;p&gt;A escolha é sua. Eu estou falando de um lugar como desenvolvedor pleno, outros textos de devs mais novos e mais experientes pode ajudar dependendo de você que tá lendo. Eu, já tomei a segunda pílula, e eu trouxe no texto (acredito ter deixado bem claro) o quanto me fez mal.&lt;/p&gt;

&lt;p&gt;Acredito que a gente precisa usar a IA como ferramenta, ela veio pra ajudar de fato, otimiza muita coisa, e tá bom. Como você pode usar? Acredito que já evitando prompts do tipo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Preciso que você ajuste a view X, está vermelha, não branca&lt;/li&gt;
&lt;li&gt;Preciso que você me ajude com esse bug aqui (aí vem um rajadão de trace do terminal)&lt;/li&gt;
&lt;li&gt;Preciso que você crie uma rota que irá devolver o payload tal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evitar esses prompts bobos (mas muito danosos) é importante, porque quando você menos ver, você já nem tá mais pensando direito, você só vai dando rajadão de linguagem natural e a IA vai se virando nos 30.&lt;/p&gt;

&lt;p&gt;Outra coisa, evitar terceirizar trabalho. “Ai, mas o meu chefe tá cobrando de usar IA”. Irmão, tu vai usar a porra da IA, mas não terceirizando. No dashboard ele não vai ter o que tu inputou (se tiver também, qual o problema?). Então evita prompts que a IA gera troucentos códigos que tu não faz nem ideia do porque ele criou a disgrasa de um concern na aplicação, imbutido num service, pra chamar no controller.&lt;/p&gt;

&lt;p&gt;Procure, em vez disso (e aqui não vou discutir prompt, então calma lá pedreiro de prompt), traga prompts que estimulem seu pensamento lógico cognitivo. Não recorra a IA primeiro, saia dessa porra de IA First. Primeiro tente pensar por você o problema, quais seriam as hipóteses, investigue. Isso não leva tanto tempo quanto a gente diz (nós devs adoramos aumentar como se as coisas fossem muito maiores do que são). Beleza, pensou? Agora, chegou num limite do que você raciocionou, aí é interessante com o apanhado de informações, perguntar para a IA se faz sentido, que caminhos e alternativas ela poderia te dar.&lt;/p&gt;

&lt;p&gt;E com isso, evite que ela construa todo o código para ti de cabo a rabo (claro, há pedaços que são chatos de se fazer, que você pode pedir pra ela dar aquela forcinha). Mas você, jovem gafanhoto, dev jr, não faça isso, você mais do que ninguém nessa terra, tem que escrever cada linha, inclusive coisas repetitivas, para fixar o conhecimento da linguagem. &lt;/p&gt;

&lt;p&gt;Em contextos que os códigos precisam de um pensamento mais complexo, em vez de pedir para a IA solucionar, opte por solicitar que ela te indique o caminho, qual seria o passo-a-passo, sem lhe fornecer código. Até para você considerar se aquilo faz sentido ou não.&lt;/p&gt;

&lt;p&gt;Último ponto que queria trazer de como usar, é a etapa final do seu trabalho: a revisão. Após você pensar, seguir o passo-a-passo, etc, peça para ela revisar, se faz sentido com requisitos, histórias de usuários ou seja lá o que for que tenham te passado de especificação. Com isso, você usa ela para dar um carimbasso no seu trampo sem te emburrecer.&lt;/p&gt;

&lt;p&gt;Dessa forma, nós enquanto devs, trabalhamos de maneira mais orgância e colaborativa com IA, conseguindo trazer satisfação pessoal no nosso dia-a-dia, tendo o famoso ownership do código (muito útil em WarRooms) e deixando nosso cérebro mais forte (porque aliás, ele é um músculo que requer treino constante para não perder o shape).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Terminator
&lt;/h2&gt;

&lt;p&gt;Bom, essa foi minha visão que eu queria passar, se você não concorda, deixa nos comentários, se concorda, também deixa a sua visão aí. Não quero bancar o paladino da IA, e falar o que tá certo e errado, é apenas minha experiência e minha visão, vai de você escolher e definir como quer usar as IAs, só tome cuidado para não cair na dependêncIA. Fé!&lt;/p&gt;

&lt;p&gt;PS.: Esse texto não foi escrito e nem revisado por IA, conforme selo de qualidade abaixo.&lt;/p&gt;

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

&lt;p&gt;Em tempo, vi ontem um vídeo sobre o outro lado da moeda do GPT, vale muito a pena ver esse vídeo da BBC: &lt;a href="https://www.youtube.com/watch?v=HEwY0WKeKjc" rel="noopener noreferrer"&gt;ChatGPT: o que você não vê&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>braziliandevs</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Resenha] Entendendo Algoritmos: Um guia ilustrado para programadores e outros curiosos - Aditya Y. Bhargava</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Fri, 04 Jul 2025 01:05:32 +0000</pubDate>
      <link>https://dev.to/v1t4o/resenha-entendendo-algoritmos-um-guia-ilustrado-para-programadores-e-outros-curiosos-aditya-y-3g44</link>
      <guid>https://dev.to/v1t4o/resenha-entendendo-algoritmos-um-guia-ilustrado-para-programadores-e-outros-curiosos-aditya-y-3g44</guid>
      <description>&lt;p&gt;Fala minha tropa, fazer uma resenha rápida aqui de uma leitura que tive recentemente, e também pra movimento esse blog que já tá enchendo de teia de aranha. Seguinte, desde alguns meses comecei a me aventurar na leitura técnica, qual gerou um primeiro artigo já publicado aqui no dev.to (&lt;a href="https://dev.to/v1t4o/resenha-programando-em-go-caio-filipini-5li"&gt;[Resenha] Programando em Go - Caio Filipini&lt;/a&gt;), e terminando essa leitura decidi embarcar no livro Entendendo Algoritmos: Um guia ilustrado para programadores e outros curiosos do Aditya Y. Bhargava, apelidado por mim carinhosamente (e acho que por muita gente), livro dos ratinhos.&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%2Fehmk3i8lmprndt1khoaa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehmk3i8lmprndt1khoaa.jpg" alt="Capa do Livro" width="718" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esse livro é um tapa na cara de muito professor (inclusive na minha na época que dei aula) por conta da sua didática. Passei uma vida na escola sem entender logaritmo, e o cara em meia dúzia de frases conseguiu me explicar a parada. É algo surreal. O grande acerto do livro é uma linguagem muito simples (acerto forte da equipe de tradução também da Novatec), além dos desenhos do autor que vão criando imagens da sua explicação.&lt;/p&gt;

&lt;p&gt;Inclusive, estava comentando com uma colega que cursa história sobre essa leitura, e até ela ficou interessada de tão bem que estava falando do livro.&lt;/p&gt;

&lt;p&gt;Mas voltando ao livro do ratinhos, o autor traz alguns assuntos que julgo muito importante para programadores (independente de nível), e que muitas vezes esquecemos os conceitos ou talvez não conseguimos aprender mesmo com a faculdade.&lt;/p&gt;

&lt;p&gt;Os 5 primeiros capítulos (que foram os que consegui compreender melhor e refiz os exemplos utilizando a linguagem Go), abordam assuntos essenciais, e versam até de nível básico a médio (não julgo tão difíceis assim). Os outros 5 são tópicos um pouco mais avançados (que inclusive terei de relê-los, pois não consegui ter tempo para aplicá-los em Go ou Ruby).&lt;/p&gt;

&lt;p&gt;O grande acerto pra mim no primeiro capítulo foi ele explicar de forma muito simples sobre Notação Big O, é nesse capítulo que ele explica em poucas linhas logaritmo de um maneira magistral. Os 4 capítulos seguintes a esse abordam Ordenação e seleção, recursão, quicksort e tabelas hash - e o acerto grande é sempre trazer quando usar, como usar, para quê usar, e as notações Big O dos algoritmos.&lt;/p&gt;

&lt;p&gt;Os outros 5 capítulos já abordam temas de uma complexidade maior, acredito inclusive que para você que deseja se aventurar, utilize materiais de apoio e leia sem muita pressa, até pegar a ideia do que é abordado (acho que assim teria aproveitado melhor, mas tá valendo para uma primeira leitura). Os assuntos versam sobre Pesquisa em largura, Algoritmo de Dijkstra, Algoritmos gulosos, Programação Dinâmica, K-vizinhos e mais uns 10 algoritmos mais complexos que não foram destrinchados. Dessa segunda parte, para mim o acerto foi ele trazer exemplos de aplicação dos algoritmos no mundo real, ou problemas conhecidos.&lt;/p&gt;

&lt;p&gt;O livro como um todo é divertido, ainda mais pelas anedotas que ele usa para criar metáforas dos algoritmos, bem como o cuidado em sempre oferecer termos que sejam acessíveis a qualquer leitor. É um baita livro também de preparação para entrevistas técnicas onde a régua é um pouco mais crítica com relação a algoritmos (acredito que a primeira metade já cubra boa parte), sendo a segunda parte mais para cadeiras e empresas que atuam com sistemas de alta complexidade.&lt;/p&gt;

&lt;p&gt;Sem me alongar mais que o necessário, acho que essa é a ideia geral. Um adendo da minha experiência com a leitura, é que para me apoiar em algumas dúvidas que tive, usei o novo pai dos burros, mais conhecido como Gemini, e com a gem de “Parceiro de programação” foi interessante ampliar um pouco o conteúdo devido a ele tentar explicar alguns trechos de código que ele mesmo gerava para exemplificar, bem como alguns exemplos de aplicação que eu solicitava. Tirando isso, essa resenha aqui é totalmente feita por uma Inteligência Humana, conforme selo abaixo.&lt;/p&gt;

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

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>algorithms</category>
      <category>leituras</category>
    </item>
    <item>
      <title>[Resenha] Programando em Go - Caio Filipini</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Thu, 08 May 2025 14:54:35 +0000</pubDate>
      <link>https://dev.to/v1t4o/resenha-programando-em-go-caio-filipini-5li</link>
      <guid>https://dev.to/v1t4o/resenha-programando-em-go-caio-filipini-5li</guid>
      <description>&lt;p&gt;Terminei recentemente o livro “Programando em Go” do Caio Filipini, e gostaria de comentar sobre algumas coisas muito bacaninhas que pude aprender.&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%2F4gmbeuv7j4dai8jtufed.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gmbeuv7j4dai8jtufed.jpg" alt="Capa do Livro - Programando em Go" width="711" height="1001"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eu já havia feito antes um curso da Udemy sobre Go, e foi até positiva a experiência, embora eu tenha achado algumas partes um pouco rasas, mas acredito que era premissa do curso, uma vez que a ideia era de ser um curso introdutório. Fora isso, tenho percebido que meu foco para cursos em vídeo online está quase zero, então pode ter sido mais culpa minha mesmo.&lt;/p&gt;

&lt;p&gt;Pois bem, pesquisando por livros da linguagem encontrei esse do Caio e decidi me aventurar, depois de anos sem ler um livro técnico era um grande desafio em que eu me colacava. Claro que durante esses anos eu li inúmeros capítulos de livros técnicos, mas até então não tinha me proposto a ler de cabo a rabo - que é algo que tenho buscado mais recentemente para me aprofundar em alguns temas.&lt;/p&gt;

&lt;p&gt;O livro se inicia com uma breve introdução, mas que já vai introduzindo elementos centrais da linguagem. Logo no segundo capítulo foi onde eu comecei a ficar envolvido com a leitura do livro, quando como se não fosse nada, após apresentar elementos de sintaxe básica, ele mostra a facilidade de implementação do quicksort em Go. Foi um dos capítulos que mais gostei.&lt;/p&gt;

&lt;p&gt;Longe de ficar descrevendo cada capítulo, acho que o sucesso do livro se dá em trazer exemplos despretensiosos, para posteriormente ir destrinchando e explicando os novos elementos que vão surgindo nos códigos - como o que é feito entre o capítulo 3 (com exemplos de pilha inclusive) e 4/5 (onde se explica os elementos de maps, slices, arrays e tipos customizáveis que aparecem no capítulo anterior).&lt;/p&gt;

&lt;p&gt;Gostei muito do capítulo sobre funções, onde pude aprofundar meus conhecimentos sobre funções de primeira classe, funções anônimas, closures e high-order functions. Junto disso, o capítulo sobre Goroutines foi importante para expandir o que aprendi no curso da Udemy, quando ele aborda a questão de channels, buffer, select, além de sincronização - coisas que até então não tinha visto, e isso ampliou muito a minha visão de como tirar proveito disso em projetos que já atuei.&lt;/p&gt;

&lt;p&gt;Por fim, os capítulos finais trabalha em cima de um exemplo que cai muito em entrevista de devs, que é um encurtador de URLs, e foi muito bacana como a cada capítulo o projeto vai se desenvolvendo, de como o autor apresenta os problemas que vão surgindo em termos de código, explicando as bibliotecas envolvidas, e fornecendo alternativas que podemos tomar para solucionar esses problemas. O ponto alto disso é o capítulo sobre a refatoração, que foi muito interessante ter esse acompanhamento com o autor de como pensar refatoração usando o que Go tem para nos oferecer - claro que só com a experiência em projetos reais para ir pegando a malícia da refatoração.&lt;/p&gt;

&lt;p&gt;Enfim, um artigo curtinho, só pra tá vivo nessa plataforma, e de uma leitura muito interessante (e importante) para minha carreira, vale muito a leitura para quem tem interesse em embarcar nesse universo de Go. Agora a ideia é desenvolver um CLI para botar em prática, sem ajuda de livro e do autor, os conhecimentos aprendidos e quem sabe logo menos volto com um artigo sobre como desenvolver esse CLI básico em Go. Até a próxima!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>books</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Minha experiência na 2ª rinha de backend com Ruby + Sinatra</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Tue, 27 Feb 2024 15:08:09 +0000</pubDate>
      <link>https://dev.to/v1t4o/minha-experiencia-na-2a-rinha-de-backend-com-ruby-sinatra-3hb7</link>
      <guid>https://dev.to/v1t4o/minha-experiencia-na-2a-rinha-de-backend-com-ruby-sinatra-3hb7</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Fala minha tropa, hoje venho aqui contar um pouco da minha experência na 2ª edição da rinha de backend. Ano passado acabei não conseguindo participar, devido ao prazo ter ficado um pouco apertado. Esse ano com o prazo mais largo, consegui fazer com folga minha versãozinha. Para conseguir submeter uma versão, pensei em utilizar o ruby com sinatra, para ver algo um pouco mais diferente - no trabalho acabo usando muito rails, dessa vez queria ver que outras possibilidades conseguiria fazer com ruby, só que de forma mais enxuta.&lt;/p&gt;

&lt;p&gt;Inspirado em algumas lives do Leandro Proença, até pensei na alternativa de fazer com ruby puro, mas preferi ficar no seguro e fazer com sinatrinha que já tinha tido oportunidade de mexer num módulo extra do treinamento da Campus Code - tendo sido também com o Leandro.&lt;/p&gt;

&lt;p&gt;Pois bem, decidido a stack, eu fiquei pensando no nome do projeto. Infelizmente é meu modus operandi (desde a época de escrever ensaios na faculdade de Letras). Peguei umas músicas do Frank Sinatra e escolhi My Way, sobretudo pelo trecho que mais parecia um meme do resultado final após rodar o Gatling:&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%2F5vj8fgarqop8e76ciba9.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%2F5vj8fgarqop8e76ciba9.png" alt="My Way" width="800" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  O Processo
&lt;/h2&gt;

&lt;p&gt;A partir disso, fiz um README boladão, e diferente do ano passado, esse ano decidi ir por baby steps. Ano passado, além de prazo apertado, eu fiquei muito ansioso com a infinidade de coisas que eu não tinha tanto conhecimento e que precisava - como o Nginx e Gatling. Isso acabou me travando. Dessa vez, me preocupei primeiro em construir as rotas, depois fui construir os serviços no docker, depois a partir do repositório &lt;a href="https://github.com/leandronsp/agostinho" rel="noopener noreferrer"&gt;agostinho&lt;/a&gt; do Leandro, pensei num adaptador de conexão com o banco junto com um pool de conexões. Trabalhei em cima das validações, em grande parte me ajudou a ler os testes do Gatling, para atender aos requisitos.&lt;/p&gt;

&lt;p&gt;Terminado a parte de desenvolvimento em si, fui criar o docker-compose baseado no repositório da rinha e fui alinhando conforme zapeava entre os repositórios. Conseguindo rodar o docker-compose, parti para instalar o JDK e baixar o Gatling para rodar os testes. Feito isso, rodei os testes do Gatling e aí começa a saga.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bugs e mais bugs…
&lt;/h2&gt;

&lt;p&gt;Ao rodar o Gatling as primeiras vezes, já estourava uns 70% as validações, tive que rever a lógica. Mas o que eu ainda não tinha percebido é que era no fluxo de requisições concorrentes que estourava os erros. Visto isso, foi quando entre inúmeros tweets da rinha, vi a importância do uso das transactions. Esse foi o primeiro item que aprendi algo, e que me ajudou a sanar grande parte dos erros.&lt;/p&gt;

&lt;p&gt;Acompanhando via Portainer, eu comecei a observar alguns erros do Nginx, então para entender o que eu estava configurando de errado, fui entender o que cada linha do Nginx significava, e com isso consegui ter maior consciência do que estava fazendo de fato. Uma abordagem que eu insistentemente tinha era de aumentar no talo as worker_connections, cheguei a colocar 60000. Não percebia que esse aumento em si não adiantava, já que minhas APIs não conseguiam atender esse volume.&lt;/p&gt;

&lt;p&gt;Após entender isso, comecei a rever as threads da aplicação e trabalhei um bom tempo em entender como orquestrar isso. Comecei a subir o puma com workers + threads, e comecei a ter alguns resultados positivos - estava usando 3 workers + 5 threads e com isso conseguia atender um pouco mais da enxurrada de requisições. Mas ainda assim após algum tempo começava a derrubar as connections do Nginx, e estourava inúmeros erros 502 e 500.&lt;/p&gt;

&lt;p&gt;Foi então que o Leandro, outra vez, me mandou uma thread do twitter em que explicou os aprendizados dele com a rinha anterior, thread essa que deixo abaixo:&lt;/p&gt;


&lt;blockquote&gt;
&lt;p&gt;Alguns ajustes no NGINX e PostgreSQL e minha versão Ruby ganha um aumento de tput que garante 46k inserts.&lt;br&gt;&lt;br&gt;"Ajuste pra cima", eles dizem. &lt;br&gt;&lt;br&gt;Não. É pra baixo. &lt;br&gt;As queries são rápidas, ñ preciso floodar a stack toda com mtos requests à espera: latência gera custo.&lt;br&gt;&lt;br&gt;Detalhes na 🧵 &lt;a href="https://t.co/cAj8Ew3XWu" rel="noopener noreferrer"&gt;pic.twitter.com/cAj8Ew3XWu&lt;/a&gt;&lt;/p&gt;— leandro • nsp (&lt;a class="mentioned-user" href="https://dev.to/leandronsp"&gt;@leandronsp&lt;/a&gt;) &lt;a href="https://twitter.com/leandronsp/status/1699568664859603184?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;September 6, 2023&lt;/a&gt;
&lt;/blockquote&gt;  

&lt;p&gt;O que me ajudou foi entender que para conseguir atender de forma efetiva eu deveria fechar a torneira no Nginx e nas threads e workers das APIs, e focar em tunar as respostas do BD. Retornei a aplicação para apenas 5 threads, no Nginx limitei à 256 worker_connections e fui entender como funcionava a pool de conexões. Foi ali que demorei grande parte. Quando retornava à essas configurações mais sóbrias, acontecia de muito cedo dropar as conexões do Nginx e das APIs, não entendia porque havia um gargalo no banco de dados. Depois de muito conversar e estudar documentações, não chegava a nenhuma conclusão. No desespero, fui ver como trabalhar com I/O assíncrono, vi alguns web servers (como o falcon, thin etc), mas nada funcionava direito. Entre bugs e mais bugs desfiz tudo e fui ler a documentação da gem Connection Pool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug com a gem Connection Pool
&lt;/h2&gt;

&lt;p&gt;Não sei por qual motivo, estava tendo problemas com o método &lt;strong&gt;checkout&lt;/strong&gt; do pool de conexões. Aparentemente, ele após o uso não estava realizando a devolução da conexão pro pool, fazendo com que a cada transaction fosse criada uma nova conexão com o banco. Isso explicava o gargalo, mas como contornar? Bom, havia o método &lt;strong&gt;checkin&lt;/strong&gt;, com isso, criei um método de abertura e de fechamento da conexão e isso começou a surtir efeito.&lt;/p&gt;

&lt;p&gt;Porém, o melhor foi utilizar o método &lt;strong&gt;with&lt;/strong&gt; - por indicação do Leandro. Indo na documentação, inclusive, eles falam que é melhor o método &lt;strong&gt;with&lt;/strong&gt; em vez do &lt;strong&gt;checkout&lt;/strong&gt; devido a instabilidades que poderiam ocorrer (às vezes é só ler a documentação né? kkkk).&lt;/p&gt;

&lt;p&gt;Enfim, com o método ajustado, consegui atender a maioria das requests, mas ainda sim tinha erros. Os últimos ajustes foi configurar no PostgreSQL 30 max_connections e 30 io_concurrency para atender o pool de 15 conexões das duas APIs. Cada API tinha 5 threadzinhas e com folga conseguiu atender as conexões repassadas pelo Nginx. Os resultados estão abaixo de uma das execuçõ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%2F0ff7ujbirsvr8qaki082.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%2F0ff7ujbirsvr8qaki082.png" alt="Image description" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações finais
&lt;/h2&gt;

&lt;p&gt;Lição aprendida é que nem sempre escalar recursos, colocar mais power de máquina, pods, réplicas etc é um caminho indicado. Às vezes é mais produtivo identificar onde é o gargalo e como otimizar e, sobretudo, fechar a torneira pode ser mais eficaz em termos de performance (e também de grana em cenários reais de empresas).&lt;/p&gt;

&lt;p&gt;Bom, dos vários temas que pude aprender nessa rinha - seja do uso de transactions, pool de conexões, threads, concorrência - foi muito importante também esse compartilhamento dos problemas e das ajudas dos colegas (seja pessoalmente, seja via tweets compartilhando as soluções). A possibilidade de ver várias das submissões e as soluções que cada um fazia me ajudou muito no processo também.&lt;/p&gt;

&lt;p&gt;Só tenho a agradecer ao Francisco Zanfranceschi por ter criado a rinha e ter fornecido essa oportunidade de tanto aprendizado. Agradecer também ao Leandro Proença pela ajuda e por todos os conteúdos que ele tem produzido. Agora vamos aguardar a live do dia 14/03 para ver em que posição fiquei, e já aguardo ansiosamente a próxima edição da rinha.&lt;/p&gt;

&lt;p&gt;Pra você que se interessou, ainda tem tempo pra fazer a sua submissão, até o dia 10/03, o link do repo é esse aqui: &lt;a href="https://github.com/zanfranceschi/rinha-de-backend-2024-q1" rel="noopener noreferrer"&gt;https://github.com/zanfranceschi/rinha-de-backend-2024-q1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Link da minha versão Ruby + Sinatra pra Ruby: &lt;a href="https://github.com/v1t4o/my_way" rel="noopener noreferrer"&gt;https://github.com/v1t4o/my_way&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>sinatra</category>
      <category>rinhadebackend</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Usando a gem Foreman</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Sun, 23 Jul 2023 15:02:45 +0000</pubDate>
      <link>https://dev.to/v1t4o/usando-a-gem-foreman-3p7m</link>
      <guid>https://dev.to/v1t4o/usando-a-gem-foreman-3p7m</guid>
      <description>&lt;p&gt;Fala minha tropa, suavidade? No último artiguinho, no fim dele eu comentei sobre a gem &lt;strong&gt;Foreman&lt;/strong&gt;, pra não ficar no ar, resolvi escrever esse artiguinho curto sobre como utilizar essa &lt;em&gt;gem&lt;/em&gt; que pode ser um adianto em muitos projetos para desenvolvimento local.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sobre o Foreman
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;Foreman&lt;/strong&gt; é uma &lt;em&gt;gem&lt;/em&gt; que facilita a nossa vida quando se trata de vários processos de uma aplicação que necessitam ser executados. Um exemplo, aqui na firma tem um legadão que ele tem uma série de processos para além do &lt;strong&gt;rails s.&lt;/strong&gt; Quando tentei executar a aplicação pela primeira vez, era meio cabaço, aí abri um três terminais só pra fazer funcionar. Só que aí, ela integrava com outro legadão que tinha outros 2 processos, e aí lá vai eu abrir mais dois terminais.&lt;/p&gt;

&lt;p&gt;Bom, se eu tivesse usado o &lt;strong&gt;Foreman&lt;/strong&gt;, teria usado apenas um terminal pra primeira app, e outro terminal pra segunda app, uma vez que eu consigo colocar dentro do arquivo de config do &lt;strong&gt;Foreman&lt;/strong&gt; os vários serviços que necessito que estejam em execução apenas uma vez, sem precisar abrir vários terminais.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usando a gem
&lt;/h2&gt;

&lt;p&gt;Primeiro passo, é você adicionar no seu projeto a gem do foreman&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'foreman'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso, rode o comandinho mais famoso dos rubistas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aí na raiz do seu projeto, você precisará criar um arquivinho chamado &lt;strong&gt;&lt;em&gt;Procfile&lt;/em&gt;&lt;/strong&gt;, onde você pode botar os processos que necessite, por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;web:    &lt;/span&gt;&lt;span class="n"&gt;rails&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;3001&lt;/span&gt;
&lt;span class="ss"&gt;worker: &lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;sidekiq&lt;/span&gt;
&lt;span class="ss"&gt;service: &lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bunny_consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veja que sem o &lt;strong&gt;Foreman&lt;/strong&gt;, eu teria que abrir três sessões do terminal para conseguir subir por completo minha app e seus serviços; já com a &lt;em&gt;gem&lt;/em&gt;, para executar esses três carinhas basta no terminal eu rodar o seguinte comando pra mágica acontecer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;foreman&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A carinha dele quando está em execução:&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%2Fm69hr0ll5sj4rirk4sqi.jpeg" 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%2Fm69hr0ll5sj4rirk4sqi.jpeg" alt="Imagem do terminal com o Foreman em execução" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusões
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;Foreman&lt;/strong&gt; ajuda muito a gente no ambiente de desenvolvimento, e acredito que seja uma mão na roda para quando chega devs novos no time, sobretudo os de nível júnior. Além disso, acho massa a questão do &lt;strong&gt;&lt;em&gt;Procfile&lt;/em&gt;&lt;/strong&gt; por funcionar meio como uma documentação do que é necessário pra app funcionar. Já peguei legados que tinha que ser meio Mãe Diná pra descobrir o que precisava rodar para aplicação funcionar. O &lt;strong&gt;Foreman&lt;/strong&gt; também tem algumas paradas maneiras de exportação em produção, que ele cria uns serviços no &lt;strong&gt;/etc/init&lt;/strong&gt; que pode ser uma mão na roda para gerenciar os serviços das aplicações no servidor. Ele também tem uma breve explicação sobre a questão de concorrência que pode ocorrer. Além dele, tem outros carinhas também, eu cheguei a mexer um cadinho com o &lt;strong&gt;Overmind&lt;/strong&gt;, que é em &lt;em&gt;Golang&lt;/em&gt;, e achei bem massa também. Mas me conta aí, que outro gerenciador de processos você conhece?&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/ddollar/foreman" rel="noopener noreferrer"&gt;https://github.com/ddollar/foreman&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.daviddollar.org/2011/05/06/introducing-foreman.html" rel="noopener noreferrer"&gt;http://blog.daviddollar.org/2011/05/06/introducing-foreman.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>ruby</category>
      <category>rails</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Aplicações Ruby On Rails com RabbitMQ: uma breve discussão sobre monolitos, microsserviços e mensageria</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Sat, 22 Jul 2023 00:01:59 +0000</pubDate>
      <link>https://dev.to/v1t4o/aplicacoes-ruby-on-rails-com-rabbitmq-uma-breve-discussao-sobre-monolitos-microsservicos-e-mensageria-5ep2</link>
      <guid>https://dev.to/v1t4o/aplicacoes-ruby-on-rails-com-rabbitmq-uma-breve-discussao-sobre-monolitos-microsservicos-e-mensageria-5ep2</guid>
      <description>&lt;p&gt;Fala tropinha, tudo certo? Bom, mês passado fiz uma palestrinha técnica na firma, e me propus a falar um cadinho sobre RabbitMQ e a arquitetura de microsserviços, envolvendo nesse caso aplicações Ruby On Rails. Meu intuito aqui não é fazer uma super indagação sobre o tema, nem me aprofundar muito na implementação, mas talvez tentar fornecer um feijão com arroz sobre o tema, sobretudo pra quem nunca viu nada sobre.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;O que é RabbitMQ? O que é mensageria?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Tomo como ponto de partida a tentativa de explicar o que é o RabbitMQ, bom, ele é um software escrito em Erlang e foi lançado pela Rabbit Technologies em 2007. Ele é um software de mensageria e implementa o protocolo AMQP (Advanced Message Queuing Protocol). Guarda essa sigla pois ela será importante quando formos implementar nas apps em rubyzin. Um outro conceito importante é que o RabbitMQ é um Message Broker, o que isso quer dizer? Que ele é um servidor que apenas recebe as mensagens e alguém consome dele, não há um processamento via RabbitMQ. Isso é importante frizar pois no início podemos acabar confundindo o RabbitMQ com um Resque/Sidekiq da vida.&lt;/p&gt;

&lt;p&gt;Sabendo disso, agora o interessante é pensarmos em que tipo de arquitetura se encaixa a aplicação do RabbitMQ, dito isto, vou entrar em uma discussão breve sobre o que seria a arquitetura monolítica e a de microsserviços.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Arquitetura Monolítica&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A arquitetura monolítica trata-se de um sistema que contempla vários módulos e funcionalidades. Se pensarmos em uma API monolítica, se trataria de uma API com várias rotas, que podem englobar pedidos, compras, produtos, clientes etc, tudo em um mesmo carinha. Isso acaba evidenciando que sistemas monolíticos envolvem processos altamente acoplados, executando como um único serviço. Além disso, em caso de pico de demanda, toda arquitetura que envolve a aplicação em si deverá ser escalada.&lt;/p&gt;

&lt;p&gt;Seguindo alguns artigos que li, que deixo no final, apresento aqui os benefícios e desafios que a arquitetura monolítica apresenta&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefícios&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implantação através da cópia do pacote&lt;/li&gt;
&lt;li&gt;Compartilhamento de memória, espaço e recursos&lt;/li&gt;
&lt;li&gt;Desempenho em alguns casos, por conter em si todos os módulos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Desafios&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alta complexidade ao longo do tempo&lt;/li&gt;
&lt;li&gt;Alto acoplamento&lt;/li&gt;
&lt;li&gt;Processo demorado de desenvolvimento e deploy&lt;/li&gt;
&lt;li&gt;Dificuldades na integração CI/CD&lt;/li&gt;
&lt;li&gt;Difícil escalonamento&lt;/li&gt;
&lt;li&gt;Uma falha derruba o sistema&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Arquitetura de Microsserviços&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Nesse tipo de arquitetura, lembra aquela APIzona que a gente conversou mais a cima, então, imagina que vamos quebrar cada setorzinho em um serviço, ou seja, em vez de uma API que contempla todos aqueles módulos, teremos um carinha pra processar pedido, outro pra processar produto, outro para processar cliente etc, é como se cada microsserviço fosse um miniaplicativo que tem a própria arquitetura e lógica de negócios, com seu próprio banco de dados - o que garante um acoplamento flexível.&lt;/p&gt;

&lt;p&gt;Novamente, a partir de alguns artigos que li, trago aqui um resumo dos benefícios e desafios da arquitetura de microsserviços.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefícios&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mais rápido desenvolver, entender e manter&lt;/li&gt;
&lt;li&gt;Autonomia através do isolamento dos ciclos de vida&lt;/li&gt;
&lt;li&gt;Aplicativo poliglota&lt;/li&gt;
&lt;li&gt;Ciclos de lançamento independentes&lt;/li&gt;
&lt;li&gt;Escalonamento individual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Desafios&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complexidade devido a ser distribuído&lt;/li&gt;
&lt;li&gt;Problema com transações distribuídas&lt;/li&gt;
&lt;li&gt;Teste abrangente torna-se mais complexo&lt;/li&gt;
&lt;li&gt;Implantação mais complexa&lt;/li&gt;
&lt;li&gt;Sobrecarga de operações&lt;/li&gt;
&lt;li&gt;Latência introduzida no tempo de resposta&lt;/li&gt;
&lt;li&gt;Banco de dados por serviço&lt;/li&gt;
&lt;li&gt;Instrumentar e monitorar ambiente&lt;/li&gt;
&lt;li&gt;Cada serviço tem sua regra de acesso&lt;/li&gt;
&lt;li&gt;Comunicação assíncrona&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Exemplo de Uso&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Tendo isso em mente, vamos focar em um case de exemplo que eu bolei para a minha apresentação. Tentei idealizar uma aplicação legada em que utilizasse processos síncronos com jobs via Sidekiq/Resque, a ideia era mais ou menos essa aqui:&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%2Fjhku7sy5mlrv43gjqj6u.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%2Fjhku7sy5mlrv43gjqj6u.png" alt="Arquitetura de um monolito" width="427" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Veja que ali temos uma aplicação, que embora seja focada em distribuir as Notificações, ela acaba por ficar responsável por vários tipos de notificações: email, sms, push. Nesse caso, minha ideia, era pegar um desses tipos e quebrar em um serviço separado, suponhamos que a gama de emails disparados fosse muito alta. Na arquitetura em monolito, para escalar eu teria que aumentar o hardware de servidor ou de rede, ou até pensar na questão do banco de dados. Agora em microsserviço, veja como ficaria o exemplo:&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%2Fepe34vxy73in7ffs1lhm.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%2Fepe34vxy73in7ffs1lhm.png" alt="Arquitetura com microsserviço" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse caso, veja que eu tenho um Service Notifications responsável apenas pelo disparo dos e-mails e mesmo que eu tivesse um aumento na demanda por disparo de e-mails, não necessitaria escalar meu monolito por inteiro, agora eu escalo somente o meu microsserviço. Eu acho essa forma de pensar e partir pros microsserviços interessante. Geralmente, por hype, as pessoas tem vendido microsserviços como bala de prata para problemas de performance dentro das empresas, mas acredito que seja mais adequado pensar a arquitetura como uma solução se o contexto apresentar as condições necessárias. &lt;/p&gt;

&lt;p&gt;Essa forma mais cautelosa, fará que você apenas escale o que de fato necessitar de um legado, e ainda o mantiver ativo enquanto seu ciclo de vida permitir. Sair de um legado para uma arquitetura de microsserviços por inteiro, pode representar um desperdício de dinheiro em infraestrutura, uma vez que você pode ter segmentado vários módulos em microsserviços que não demandam tanto, representando máquinas ociosas, espaço em banco de dados alocado sem uso, entre outros impactos desnecessários. Enfim, o papo tá bom, mas como funciona o processo? Vamos lá, dividi em dois momentos a implementação em aplicações Ruby On Rails. Primeiro ponto é o Publisher e o segundo o Consumer.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Implementação&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Publisher&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Primeira coisa que fiz nesse exemplo acima, foi na aplicação Notifications incluir a gem do Bunny no Gemfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;gem&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bunny&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após isso, rode o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;bundle&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O segundo passo, é criarmos na pasta lib o arquivo bunny_client.rb com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;frozen_string_literal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BunnyClient&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&amp;lt; &lt;/span&gt;&lt;span class="nc"&gt;self&lt;/span&gt;

        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Cria&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;conexão&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;RabbitMQ&lt;/span&gt;
        &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
            &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Utiliza&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;variável&lt;/span&gt; &lt;span class="nx"&gt;CLOUDAMQP_URL&lt;/span&gt; &lt;span class="nx"&gt;para&lt;/span&gt; &lt;span class="nx"&gt;conectar&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="nx"&gt;indicado&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Bunny&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="nx"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUDAMQP_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;
            &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Cria&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;canal&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create_channel&lt;/span&gt;
            &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Cria&lt;/span&gt; &lt;span class="nx"&gt;nossa&lt;/span&gt; &lt;span class="nx"&gt;fila&lt;/span&gt; &lt;span class="nx"&gt;para&lt;/span&gt; &lt;span class="nx"&gt;onde&lt;/span&gt; &lt;span class="nx"&gt;vamos&lt;/span&gt; &lt;span class="nx"&gt;publicar&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mensagens&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;fan_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fanout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notifications_email.out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="nx"&gt;end&lt;/span&gt;

        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Publica&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mensagens&lt;/span&gt; &lt;span class="nx"&gt;na&lt;/span&gt; &lt;span class="nx"&gt;fila&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;informando&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;origem&lt;/span&gt; &lt;span class="nx"&gt;da&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
        &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;connected&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;fan_out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;app_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notifications_email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="nx"&gt;end&lt;/span&gt;
    &lt;span class="nx"&gt;end&lt;/span&gt;
&lt;span class="nx"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crie um arquivo em config/initializers chamado bunny.rb com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;require&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bunny&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;require&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bunny_client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No seu arquivo .env, não esqueça de adicionar a seguinte variável de ambiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CLOUDAMQP_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amqp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:5672&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma, dentro do fluxo da sua app, vamos supor que você tenha um model que após salvar localmente numa base de dados, você queira encaminhar para uma fila onde o microsserviço irá processar, você pode fazer algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;ApplicationRecord&lt;/span&gt;
    &lt;span class="nx"&gt;after_save&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;    
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Aqui&lt;/span&gt; &lt;span class="nx"&gt;um&lt;/span&gt; &lt;span class="nx"&gt;exemplo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;estamos&lt;/span&gt; &lt;span class="nx"&gt;utilizando&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;método&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="nx"&gt;que&lt;/span&gt; &lt;span class="nx"&gt;criamos&lt;/span&gt; &lt;span class="nx"&gt;acima&lt;/span&gt;
        &lt;span class="nx"&gt;BunnyClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;end&lt;/span&gt;
&lt;span class="nx"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para fazer funcionar na sua app, basta rodar o bom e velho &lt;strong&gt;rails s&lt;/strong&gt; e bater na rota de criação por exemplo, para ver o funcionamento da publicação na fila.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Consumer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No microsserviço, seguimos o mesmos passos iniciais que é incluir a gem do Bunny no Gemfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;gem&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bunny&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após isso, rode o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;bundle&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No seu arquivo .env, não esqueça de adicionar a seguinte variável de ambiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CLOUDAMQP_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amqp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:5672&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após isso, precisamos criar um arquivo na pasta bin chamado bunny_consumer.rb com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/usr/bin/env ruby
&lt;/span&gt;
&lt;span class="nx"&gt;require&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config/environment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;__dir__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Cria&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;conexão&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;RabbitMQ&lt;/span&gt;
&lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Bunny&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="nx"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUDAMQP_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;
&lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create_channel&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Cria&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;fila&lt;/span&gt; &lt;span class="nx"&gt;para&lt;/span&gt; &lt;span class="nx"&gt;processamento&lt;/span&gt;
&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notifications_email.in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;durable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;auto_delete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;puts&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Starting consumer!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Captura&lt;/span&gt; &lt;span class="nx"&gt;da&lt;/span&gt; &lt;span class="nx"&gt;fila&lt;/span&gt; &lt;span class="nf"&gt;out &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;que&lt;/span&gt; &lt;span class="nx"&gt;usamos&lt;/span&gt; &lt;span class="nx"&gt;na&lt;/span&gt; &lt;span class="nx"&gt;outra&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mensagens&lt;/span&gt; &lt;span class="nx"&gt;existentes&lt;/span&gt;
&lt;span class="nx"&gt;fanout_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notifications_email.out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fanout_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fanout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;puts&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[consumer] #{queue.name} binds to #{fanout_name}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Inicia&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;processamento&lt;/span&gt; &lt;span class="nx"&gt;da&lt;/span&gt; &lt;span class="nx"&gt;mensagem&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Nesse&lt;/span&gt; &lt;span class="nx"&gt;nosso&lt;/span&gt; &lt;span class="nx"&gt;exemplo&lt;/span&gt; &lt;span class="nx"&gt;aqui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vamos&lt;/span&gt; &lt;span class="nx"&gt;utilizar&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;Modelo&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;para&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;qual&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Vamos&lt;/span&gt; &lt;span class="nx"&gt;salvar&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt; &lt;span class="nx"&gt;para&lt;/span&gt; &lt;span class="nx"&gt;ter&lt;/span&gt; &lt;span class="nx"&gt;um&lt;/span&gt; &lt;span class="nx"&gt;histórico&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="nx"&gt;envio&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Mas&lt;/span&gt; &lt;span class="nx"&gt;poderia&lt;/span&gt; &lt;span class="nx"&gt;se&lt;/span&gt; &lt;span class="nx"&gt;tratar&lt;/span&gt; &lt;span class="nx"&gt;também&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;usar&lt;/span&gt; &lt;span class="nx"&gt;diretamente&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="nx"&gt;mailer&lt;/span&gt;
&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;d_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_and_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;puts&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[consumer] #{queue.name} received #{properties[:type]}, from #{properties[:app_id]}: #{payload}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;end&lt;/span&gt;

&lt;span class="nx"&gt;begin&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;end&lt;/span&gt;
&lt;span class="nx"&gt;rescue&lt;/span&gt; &lt;span class="nx"&gt;Interrupt&lt;/span&gt;
    &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;
    &lt;span class="nx"&gt;puts&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Shutting down gracefully.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;exit&lt;/span&gt;
&lt;span class="nx"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rode o seguinte comando no terminal, para tornar esse arquivo executável:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;sudo&lt;/span&gt; &lt;span class="nx"&gt;chmod&lt;/span&gt; &lt;span class="mi"&gt;755&lt;/span&gt; &lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bunny_consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lá no nosso model de Email, a implementação da chamada a partir do BunnyConsumer ficaria dessa forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_and_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
    &lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="nx"&gt;end&lt;/span&gt;

  &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;MessageMailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deliver_now&lt;/span&gt;
  &lt;span class="nx"&gt;end&lt;/span&gt;
&lt;span class="nx"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veja que aqui eu consigo criar localmente o e-mail e logo após faço o envio do e-mail. Observe que esse microsserviço ele fica responsável apenas por processar isto, não há requisição ou qualquer outra coisa.&lt;/p&gt;

&lt;p&gt;Por fim, para fazer funcionar esse carinha, basta rodar o comandinho:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bunny_consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claro, você pode criar rotas para consultar esses dados no microsserviço se quiser, em vez da aplicação legada, basta criar um &lt;em&gt;Procfile&lt;/em&gt; com ambos os comandos abaixo, e utilizar a gem do &lt;strong&gt;Foreman&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;rails&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;5002&lt;/span&gt;
&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bunny_consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusões&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Bom, espero que esse artiguinho ajude a introduzir a vocês um pouquinho dos conceitos de monolitos, microsserviços e mensageria com RabbitMQ. Volto a bater na tecla de que microsserviços não é bala de prata, é preciso considerar os contextos e necessidades. Entretanto, pode ser uma arquitetura que seja um trunfo em contextos de serviços que tenham uma demanda crescente e que vira e mexe necessitam de algum tipo de escalabilidade.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://aws.amazon.com/pt/microservices/" rel="noopener noreferrer"&gt;https://aws.amazon.com/pt/microservices/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/learn/what-is-microservices-architecture?hl=pt-br" rel="noopener noreferrer"&gt;https://cloud.google.com/learn/what-is-microservices-architecture?hl=pt-br&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@marcelomg21/arquitetura-de-microsservi%C3%A7os-bc38d03fbf64" rel="noopener noreferrer"&gt;https://medium.com/@marcelomg21/arquitetura-de-microsserviços-bc38d03fbf64&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ruby-amqp/bunny" rel="noopener noreferrer"&gt;https://github.com/ruby-amqp/bunny&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://world.hey.com/dhh/how-to-recover-from-microservices-ce3803cc" rel="noopener noreferrer"&gt;https://world.hey.com/dhh/how-to-recover-from-microservices-ce3803cc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>ruby</category>
      <category>rails</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Implementação do Flipper para controle de features</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Fri, 02 Jun 2023 15:19:42 +0000</pubDate>
      <link>https://dev.to/v1t4o/implementacao-do-flipper-para-controle-de-features-3l4j</link>
      <guid>https://dev.to/v1t4o/implementacao-do-flipper-para-controle-de-features-3l4j</guid>
      <description>&lt;p&gt;Fala tropinha, hoje venho trazer uma gemzinha braba também, que pode ajudar no dia-a-dia. A gem em questão é a Flipper, e ela é uma gem que fornece features flags que pode auxiliar você à controlar o acesso à determinadas features ainda em desenvolvimento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalação e Configuração
&lt;/h2&gt;

&lt;p&gt;Para instalação, basta adicionar no seu Gemfile a gem flipper e a flipper-ui&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="s1"&gt;'flipper'&lt;/span&gt;
gem &lt;span class="s1"&gt;'flipper-ui'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Além dessas duas, ainda devemos adicionar uma outra gem adapter, para termos onde guardar nossas flags. Vou utilizar aqui a do Redis, que tenho visto ser mais comum, mas pode ser que na sua empresa eles acabem optando por salvar no BD. Na documentação oficial, tem os adaptadores que conectam no banco e cada um tem sua doczinha bonitinha.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="s1"&gt;'flipper-redis'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso, basta rodar o bundle. Na pasta config/initializers crie o arquivo flipper.rb com o seguinte conteúdo para configurarmos o Redis como o local onde será guardado as features flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;require &lt;span class="s1"&gt;'flipper/adapters/redis'&lt;/span&gt;

Flipper.configure &lt;span class="k"&gt;do&lt;/span&gt; |config|
  config.adapter &lt;span class="o"&gt;{&lt;/span&gt; Flipper::Adapters::Redis.new&lt;span class="o"&gt;(&lt;/span&gt;Redis.new&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para configurar o acesso à UI do Flipper, você precisa fazer o processo de montagem da rota. Entre no arquivo routes.rb, e adicione a seguinte linha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mount Flipper::UI.app&lt;span class="o"&gt;(&lt;/span&gt;Flipper&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'/flipper'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa rota, se for necessário (e quase sempre é kkkk), tem como você protegê-la, na documentação tem algumas dicas. Não vou avançar muito aqui, pois depende um pouco de como cada empresa em que a gente trampa lida com isso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface para criação das features flags
&lt;/h2&gt;

&lt;p&gt;Após subir sua aplicação, tente bater na rota /flipper e irá aparecer essa telinha:&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%2Fcc2e5dnyu7pisi1iyacu.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%2Fcc2e5dnyu7pisi1iyacu.png" alt="Home - Flipper" width="588" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para adicionar alguma feature, basta clicar em Add Feature, e aparecerá a seguinte telinha:&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%2Ftqs5dugdpl83bchiciux.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%2Ftqs5dugdpl83bchiciux.png" alt="Added Feature in Flipper" width="594" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Escolha um nome para a sua feature flag, em breve mostrarei como implementar isso no código. Ao prosseguir, aparece uma tela com algumas opções que temos em cada feature flag criada:&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%2F2yt6nspvzkmabw9lulab.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%2F2yt6nspvzkmabw9lulab.png" alt="Feature Flag Options" width="601" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O Flipper é uma mão na roda pra algumas coisas do dia-a-dia. Por exemplo, temos ali a opção de actors. Digamos que há um determinado fluxo da sua aplicação que tem gerado alguns erros para alguns clientes. Podemos usar essa opção para indicar os IDs desses clientes, e aplicar apenas para eles a solução de contorno. Podemos fazer isso também habilitando por grupos, como mostrado na tela acima.&lt;/p&gt;

&lt;p&gt;Um outro cenário interessante de aplicação. Digamos que foi criado algum novo serviço para solucionar uma consulta, mas antes de fazer a troca em produção, você pensa em ir testando aos poucos. Tem como você habilitar uma certa porcentagem de usuários ou por tempo, e isso faz com que você consiga ir escalando essa quantidade, até perceber que pode mudar o fluxo na aplicação sem trazer grandes impactos aos clientes.&lt;/p&gt;

&lt;p&gt;Tá, mas até agora só falei do Flipper, como isso se aplica no código? Bom, é bem tranquilo. Criei uma aplicação rails e gerei um scaffold para Car. Vou mostrar como isso poderia ser utilizado no controller, na parte de edit, e na view com o botão de deletar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uso dentro do código e testes
&lt;/h2&gt;

&lt;p&gt;Bom, estamos aqui no cars_controller.rb, e veja que é bem tranquilo para utilizar o Flipper.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;edit&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:show&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:edit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No método de edit, eu coloquei uma verificação para que caso a feature flag :edit não esteja habilitada, eu renderize o show  do car. Caso esteja habilitada, ela prosseguirá o fluxo normal e com isso conseguirei editar o item.&lt;/p&gt;

&lt;p&gt;Na view não é muito diferente esse processo, no arquivo show.html.erb, fiz algo bem parecido, envolvendo o botão de destroy em um if que só vai exibir se a feature flag estiver habilitada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% if &lt;/span&gt;&lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:destroy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= button_to "Destroy this car", @car, method: :delete %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um cuidado importante que se deve ter ao utilizar features flags do Flipper, é que ao deletar, ela deixa de existir em todo o sistema. Com isso, lembre-se de tirar a verificação da feature flag dos trechos de códigos onde você acabou usando por algum momento as flags.&lt;/p&gt;

&lt;p&gt;E como ficaria ao criarmos testes? Bom, o processo é bem semelhante. Eu consigo, dentro dos testes, desabilitar ou habilitar alguma flag usando os métodos enable ou disable, e com isso simular os fluxos, veja abaixo um exemplo de teste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"Feature Flags"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
 &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;"destroy a car"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'when feature flag is disabled'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:destroy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Car&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="ss"&gt;make: &lt;/span&gt;&lt;span class="s2"&gt;"Ford"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="s2"&gt;"Ká"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;color: &lt;/span&gt;&lt;span class="s2"&gt;"Red"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;year: &lt;/span&gt;&lt;span class="s2"&gt;"2023"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="s2"&gt;"R$ 30.000,00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;cars_path&lt;/span&gt;
    &lt;span class="n"&gt;click_on&lt;/span&gt; &lt;span class="s2"&gt;"Show this car"&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="n"&gt;have_button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Destroy this car"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'when feature flag is enabled'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:destroy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Car&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="ss"&gt;make: &lt;/span&gt;&lt;span class="s2"&gt;"Ford"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="s2"&gt;"Ká"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;color: &lt;/span&gt;&lt;span class="s2"&gt;"Red"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;year: &lt;/span&gt;&lt;span class="s2"&gt;"2023"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;price: &lt;/span&gt;&lt;span class="s2"&gt;"R$ 30.000,00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;cars_path&lt;/span&gt;
    &lt;span class="n"&gt;click_on&lt;/span&gt; &lt;span class="s2"&gt;"Show this car"&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Destroy this car"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Considerações Finais
&lt;/h2&gt;

&lt;p&gt;Bom, meu intuito era apresentar essa ferramenta, que pode ser muito útil no nosso dia-a-dia. Um uso interessante que notamos aqui na minha empresa atual, é de que em soluções críticas, que podem gerar impactos ao cliente, talvez testar a solução colocando uma feature flag seja mais interessante no ambiente de produção, uma vez que evita o processo de rollback. &lt;/p&gt;

&lt;p&gt;Além disso, com alguns controles do Flipper, é possível ir escalando a quantidade de clientes que podem ter acesso ou não à determinada feature, isso evita um impacto negativo no lançamento de uma nova feature. Observamos uma oportunidade interessante de usá-la também para reduzir quantidade de rollbacks e até como solução de contorno rápida para alguns problemas com prioridade alta.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/jnunemaker/flipper" rel="noopener noreferrer"&gt;https://github.com/jnunemaker/flipper&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.flippercloud.io/docs/introduction" rel="noopener noreferrer"&gt;Flipper Documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>ruby</category>
      <category>rails</category>
      <category>flipper</category>
    </item>
    <item>
      <title>Usando a gem httplog para uma melhor análise dos logs</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Wed, 19 Apr 2023 12:01:16 +0000</pubDate>
      <link>https://dev.to/v1t4o/usando-a-gem-httplog-para-uma-melhor-analise-dos-logs-j5l</link>
      <guid>https://dev.to/v1t4o/usando-a-gem-httplog-para-uma-melhor-analise-dos-logs-j5l</guid>
      <description>&lt;p&gt;Fala tropinha, tudo bom? Venho trazer nesse artiguinho minúsculo, um pouquinho sobre uma gem que tenho usado no dia-a-dia do trabalho para fazer alguns mapeamentos e documentação de aplicações legadas. A gem em questão é a &lt;strong&gt;httplog&lt;/strong&gt;, e achei ela bem interessante por conseguir me exibir em detalhes os dados das requisições que são feitas para as mais diversas aplicações.&lt;/p&gt;

&lt;p&gt;Para configurar ela, o primeiro passo é adicionar a gem no &lt;strong&gt;Gemfile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="s1"&gt;'httplog'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso basta rodar o seguinte comando no terminal, dentro da sua pasta do projeto rails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O último passo é você criar dentro da pasta &lt;strong&gt;config/initializers&lt;/strong&gt; o arquivo &lt;strong&gt;httplog.rb&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;HttpLog.configure &lt;span class="k"&gt;do&lt;/span&gt; |config|

  &lt;span class="c"&gt;# Enable or disable all logging&lt;/span&gt;
  config.enabled &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;

  &lt;span class="c"&gt;# You can assign a different logger or method to call on that logger&lt;/span&gt;
  config.logger &lt;span class="o"&gt;=&lt;/span&gt; Logger.new&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stdout&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  config.logger_method &lt;span class="o"&gt;=&lt;/span&gt; :log

  &lt;span class="c"&gt;# I really wouldn't change this...&lt;/span&gt;
  config.severity &lt;span class="o"&gt;=&lt;/span&gt; Logger::Severity::DEBUG

  &lt;span class="c"&gt;# Tweak which parts of the HTTP cycle to log...&lt;/span&gt;
  config.log_connect   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;config.log_request   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;config.log_headers   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false
  &lt;/span&gt;config.log_data      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;config.log_status    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;config.log_response  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;config.log_benchmark &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;

  &lt;span class="c"&gt;# ...or log all request as a single line by setting this to `true`&lt;/span&gt;
  config.compact_log &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;

  &lt;span class="c"&gt;# You can also log in JSON format&lt;/span&gt;
  config.json_log &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;

  &lt;span class="c"&gt;# Prettify the output - see below&lt;/span&gt;
  config.color &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;

  &lt;span class="c"&gt;# Limit logging based on URL patterns&lt;/span&gt;
  config.url_whitelist_pattern &lt;span class="o"&gt;=&lt;/span&gt; nil
  config.url_blacklist_pattern &lt;span class="o"&gt;=&lt;/span&gt; nil

  &lt;span class="c"&gt;# Mask sensitive information in request and response JSON data.&lt;/span&gt;
  &lt;span class="c"&gt;# Enable global JSON masking by setting the parameter to `/.*/`&lt;/span&gt;
  config.url_masked_body_pattern &lt;span class="o"&gt;=&lt;/span&gt; nil

  &lt;span class="c"&gt;# You can specify any custom JSON serializer that implements `load` and `dump` class methods&lt;/span&gt;
  &lt;span class="c"&gt;# to parse JSON responses&lt;/span&gt;
  config.json_parser &lt;span class="o"&gt;=&lt;/span&gt; JSON

  &lt;span class="c"&gt;# When using graylog, you can supply a formatter here - see below for details&lt;/span&gt;
  config.graylog_formatter &lt;span class="o"&gt;=&lt;/span&gt; nil

  &lt;span class="c"&gt;# Mask the values of sensitive request parameters&lt;/span&gt;
  config.filter_parameters &lt;span class="o"&gt;=&lt;/span&gt; %w[password]

  &lt;span class="c"&gt;# Customize the prefix with a proc or lambda&lt;/span&gt;
  config.prefix &lt;span class="o"&gt;=&lt;/span&gt; -&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"[httplog] #{Time.now} "&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prontinho, assim quando você subir a aplicação, ele carrega o &lt;strong&gt;httplog&lt;/strong&gt; e você consegue ter uma visão um pouquinho melhor de cada request feita para outras aplicações. Tem como ainda naquele arquivinho que criamos nos &lt;strong&gt;initializers&lt;/strong&gt; ajustar o texto exibido, cor, filtrar parâmetros, entre outros itens que estão disponíveis no arquivo de configuração.&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%2Fzxwwmd7m33pi05vgjtrp.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%2Fzxwwmd7m33pi05vgjtrp.png" alt="Imagem-do-Terminal-com-Logs" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caso você prefira não ficar vendo os logs pelo terminal, tem como ajustar para ele salvar em um arquivo de log, basta alterar a linha 7 do arquivo &lt;strong&gt;httplog.rb&lt;/strong&gt; para:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;config.logger &lt;span class="o"&gt;=&lt;/span&gt; Logger.new&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'log/development.log'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bom, por hoje é só, espero ter ajudado. Se você conhecer alguma outra gem que ajuda a ter uma melhor visão dos logs, comenta aí abaixo. Tmj!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link da gem:&lt;/strong&gt; &lt;a href="https://github.com/trusche/httplog" rel="noopener noreferrer"&gt;https://github.com/trusche/httplog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>ruby</category>
      <category>rails</category>
      <category>gem</category>
    </item>
    <item>
      <title>Uso do Portainer para administração de contêineres do Docker</title>
      <dc:creator>Victor de Oliveira Marinho</dc:creator>
      <pubDate>Fri, 17 Mar 2023 14:07:51 +0000</pubDate>
      <link>https://dev.to/v1t4o/uso-do-portainer-para-administracao-de-conteineres-do-docker-3ilg</link>
      <guid>https://dev.to/v1t4o/uso-do-portainer-para-administracao-de-conteineres-do-docker-3ilg</guid>
      <description>&lt;p&gt;Fala minha tropa, tranquilidade? Nesse primeiro artigo aqui na &lt;a href="http://dev.to"&gt;dev.to&lt;/a&gt; eu quero falar um pouquinho sobre o uso do &lt;strong&gt;Portainer&lt;/strong&gt; para gerenciamento de contêineres do &lt;strong&gt;Docker&lt;/strong&gt;. Essa dica foi um parceiro do meu trampo que me passou, vou compartilhar com geral pra ajudar no dia-a-dia.&lt;/p&gt;

&lt;p&gt;Usar o &lt;strong&gt;Docker&lt;/strong&gt; só via terminal é massa, mas devido à correria do dia-a-dia às vezes vale a pena ter disponível algo pra gerenciar de forma mais fácil. Dessa forma, o &lt;strong&gt;Portainer&lt;/strong&gt; é uma boa solução.&lt;/p&gt;

&lt;p&gt;Se você ainda não tem o dockerzão instalado na sua máquina, tem esse tutorial brabo de &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04" rel="noopener noreferrer"&gt;Docker na Digital Ocean&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pois bem, para tê-lo na sua máquina, o primeiro passo é você rodar esse comando para criar um volume para os dados do &lt;strong&gt;Portainer&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create portainer_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso, tu precisa rodar o seguinte comando para baixar a imagem do &lt;strong&gt;Portainer&lt;/strong&gt; e mapear os volumes para gerenciar o &lt;strong&gt;Docker&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 &lt;span class="nt"&gt;-p&lt;/span&gt; 9443:9443 &lt;span class="nt"&gt;--name&lt;/span&gt; portainer &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="nt"&gt;-v&lt;/span&gt; /var/run/docker.sock:/var/run/docker.sock &lt;span class="nt"&gt;-v&lt;/span&gt; portainer_data:/data portainer/portainer-ce:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para saber o que cada coisa significa, segue abaixo uma listinha com a descrição das paradas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-d&lt;/strong&gt; - essa opção faz com que o container funcione em background&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-p&lt;/strong&gt; - essa opção faz com que seja mapeada a porta 9443 para acesso via navegador na porta default do &lt;strong&gt;Portainer&lt;/strong&gt; (9443) [segundo documentação]. Vale lembrar que você pode alterar essa porta, poderíamos ter utilizado 9000:9000, por exemplo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;--name&lt;/strong&gt; - é o nome do container a ser criado&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;--restart=always&lt;/strong&gt; - isso faz com que o container reinicie automaticamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-v /var/run/docker.sock:/var/run/docker.sock&lt;/strong&gt; - mapeia o volume do container para gerenciamento dos outros contêineres do ambiente &lt;strong&gt;Docker&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-v portainer_data:/data&lt;/strong&gt; - mapeia o volume referente aos dados do &lt;strong&gt;Portainer&lt;/strong&gt; que criamos antes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;portainer/portainer-ce:latest&lt;/strong&gt; - indica qual imagem do &lt;strong&gt;Portainer&lt;/strong&gt; será utilizada&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bom, depois dos comandos terem rodados, é só você acessar via navegador na URL: &lt;a href="https://localhost:9443/" rel="noopener noreferrer"&gt;https://localhost:9443&lt;/a&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%2Fgv9t6x4ncww68w37qjgw.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%2Fgv9t6x4ncww68w37qjgw.png" alt="Tela inicial do Portainer de configuração de usuário admin" width="800" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No primeiro acesso, ele pedirá para você cadastrar uma senha pro admin. Basta preencher bonitinho e concluir pra ter acesso ao painelzinho do &lt;strong&gt;Portainer&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%2Fgxmbihjsd4bj5e09pv7a.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%2Fgxmbihjsd4bj5e09pv7a.png" alt="Tela inicial do Portainer" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No &lt;strong&gt;Portainer&lt;/strong&gt; há várias funcionalidades, você tem uma dashboard informando os ambientes disponíveis:&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%2Fg9rfxvh105bv1ral6f19.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%2Fg9rfxvh105bv1ral6f19.png" alt="Listagem dos ambientes do Docker no Portainer" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Você também tem uma dashboard por ambiente dos contêineres, volumes, imagens, redes criadas:&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%2Ffw2kddliz5ot2ze486ax.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%2Ffw2kddliz5ot2ze486ax.png" alt="Dashboard de um dos ambientes do Docker" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na listagem dos contêineres, você tem a opção também de visualizar os status, parar ou iniciar um container específico. Há também como adicionar novos contêineres por aqui. &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%2F6xcnuyuvkhkkvadvdvfg.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%2F6xcnuyuvkhkkvadvdvfg.png" alt="Listagem dos contêineres de um ambiente do Docker" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicando em um deles, você consegue visualizar mais informações, como operações dos contêineres, status, acesso à logs e terminal.&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%2Fe2wbxmcmi8hfm7lfwqof.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%2Fe2wbxmcmi8hfm7lfwqof.png" alt="Visualização de informações de um container em específico" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bom, basicamente é isso, o intuito aqui era mais apresentar a ferramenta, que tem salvado muito no dia-a-dia do meu trampo. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fontes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.portainer.io/start/install-ce/server/docker/linux" rel="noopener noreferrer"&gt;https://docs.portainer.io/start/install-ce/server/docker/linux&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>portainer</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
