<?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: Scarlet Rose</title>
    <description>The latest articles on DEV Community by Scarlet Rose (@scarlet).</description>
    <link>https://dev.to/scarlet</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%2F1163885%2F35b53614-51c1-4278-b7ea-4af3faf21dfa.jpg</url>
      <title>DEV Community: Scarlet Rose</title>
      <link>https://dev.to/scarlet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/scarlet"/>
    <language>en</language>
    <item>
      <title>[BR] Arquiteturas híbridas - entrelaçando monólitos, microsserviços e serviços distribuídos</title>
      <dc:creator>Scarlet Rose</dc:creator>
      <pubDate>Wed, 08 Jan 2025 21:53:04 +0000</pubDate>
      <link>https://dev.to/scarlet/br-arquiteturas-hibridas-entrelacando-monolitos-microsservicos-e-servicos-distribuidos-3mk8</link>
      <guid>https://dev.to/scarlet/br-arquiteturas-hibridas-entrelacando-monolitos-microsservicos-e-servicos-distribuidos-3mk8</guid>
      <description>&lt;p&gt;Vejo muitas pessoas (algumas até mesmo abominam a ideia, no mesmo naipe daquele pessoal que odeia modinhas novas em memes) receosas a respeito da construção de serviços distribuídos e microsserviços, muitas até imaginando um processo big-bang, que demandaria custos absurdos e causaria problemas difíceis de serem resolvidos.&lt;/p&gt;

&lt;p&gt;Mas não é bem assim, a implantação de microsserviços não precisa necessariamente ser uma operação atômica, e nem mesmo definitiva! A arquitetura de uma solução não necessita seguir apenas um padrão em sua integridade, e nem precisa se manter a mesma permanentemente.&lt;/p&gt;

&lt;p&gt;Esses são os motivos pelos quais eu acredito no poder das arquiteturas distribuídas e microsserviços:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uma solução completa é uma união de vários artefatos, um monólito que começou hoje pode, em alguns meses, ter uma funcionalidade crítica que precise ser abstraída para um serviço separado e escalada individualmente, e tá tudo bem!&lt;/li&gt;
&lt;li&gt;É possível que o time de engenharia e arquitetura entre em um consenso de que para exercer determinada função, é necessário começar com serviços distribuídos do zero, database não é o gargalo aqui, assincronismo e recursos sim, e tá tudo bem.&lt;/li&gt;
&lt;li&gt;Talvez existam centenas (ou milhares) de desenvolvedores que atuam em um mesmo produto (incomum, mas WOW!) e manter o código-fonte em um mesmo projeto pode causar desde conflitos de código até uma (e diga-se de passagem) longa fila de espera para que uma squad específica possa colocar seu trecho de código em produção&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Escala é sobre pessoas. Desenvolvimento é uma atividade sociológica. E não, esses padrões de arquitetura não são uma bala de prata, nenhum é, afinal o importante é ter sua aplicação disponível em produção, gerando receita e agregando a vida de seus clientes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entendendo o que é uma arquitetura híbrida
&lt;/h2&gt;

&lt;p&gt;Quando falamos de arquitetura de software, pensamos em algo como um monólito bem estruturado utilizando algo como &lt;em&gt;onion architecture&lt;/em&gt; ou &lt;em&gt;arquitetura hexagonal&lt;/em&gt; para que todas as suas peças estejam no lugar certo, ou até mesmo em uma estrutura de serviços escaláveis de maneira isolada que se conectam de maneira distribuída a um mesmo banco de dados, ou por fim, a famosa arquitetura de microsserviços, onde todas as operações são isoladas com o objetivo de evitar a manutenção de um único ponto de falha. Acontece que na prática não é bem assim. Fora de empresas tecnológicas que já são consolidadas a uns bons anos, arquiteturas que podem ser consideradas "perfeitas" por muitos são raras e (de maneira esperada) não vão existir, ou ao menos não vão funcionar como todos imaginariam. No contexto &lt;strong&gt;deste artigo&lt;/strong&gt;, irei considerar uma arquitetura híbrida como aquela arquitetura que está se adaptando a um novo desafio, mas não deixarei de informar que também podem ser arquiteturas que já venceram certo desafio e encontraram o "nirvana" onde o nível de estabilidade é alto ao mesmo tempo que fogem de conceitos tradicionais e enraizados.&lt;/p&gt;

&lt;p&gt;Em resumo, arquitetura híbrida é aquela que &lt;em&gt;utiliza dois ou mais conceitos para alcançar determinado objetivo de escalonamento&lt;/em&gt;. Pense num monólito de onde foram abstraídos &lt;strong&gt;3 serviços moderados&lt;/strong&gt; que ainda utilizam um mesmo banco de dados e &lt;strong&gt;2 serviços críticos&lt;/strong&gt; que contam com nível de isolamento algo, com seus próprios bancos de dados. Isso é uma arquitetura híbrida, fazer algo acontecer a partir da orquestração de diversos conceitos - otimizando custos, cargas de trabalho, tempo de desenvolvimento e disponibilidade no que realmente precisa, e isso não é fácil de fazer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vantagens de se usar uma arquitetura híbrida
&lt;/h2&gt;

&lt;p&gt;Não, não existem vantagens no estilo "bala de prata". O que existem são vantagens situacionais que podem ser observadas em momentos onde você precisa escalar X, mas não precisa escalar Y e Z, vamos a um exemplo mais concreto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gateway de pagamentos
&lt;/h3&gt;

&lt;p&gt;Um gateway de pagamentos, surgido da necessidade de oferecer uma interface simples de pagamentos para empresas que buscam contingência e diversificação nas suas transações começou como um monólito, lá, internamente o mesmo era dividido pelas seguintes funcionalidades que acessavam um único banco de dados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Users&lt;/strong&gt; - funcionalidade interna de gerenciamento de usuários, nesse caso, os clientes. Conta com sub-módulos de autenticação, perfis internos, preferências e suporte;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wallet&lt;/strong&gt; - carrega o ledger e a montagem de operações únicas que a plataforma vai fazer para garantir integridade em todos os pagamentos, além de conter uma ou mais "balanças" para controlar o faturamento dos clientes bem como seus objetivos;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments&lt;/strong&gt; - carrega as implementações de diferentes integrações bancárias, criptomoedas, fintechs e até outros gateways de pagamentos em uma interface única, fácil de usar para o cliente;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Receipts&lt;/strong&gt; - responsável por triangular as informações de &lt;strong&gt;Payments&lt;/strong&gt; e &lt;strong&gt;Wallet&lt;/strong&gt; e executar operações como geração de notas fiscais, demandas do banco central (e outros órgãos envolvidos) e gerar arquivos de comprovante e receitas dos mais diversos tipos além de manter arquivos de outras plataformas acessíveis para operações internas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Parece que temos aqui um sistema hipoteticamente coeso que irá tratar de pagamentos, a stack nesse caso pode ser qualquer uma, desde que seja levado em consideração que o backend é um &lt;em&gt;monólito&lt;/em&gt; e o banco de dados é &lt;em&gt;único&lt;/em&gt;. Perfeito, temos a nossa base. &lt;/p&gt;

&lt;p&gt;Imagine que a solução funciona perfeitamente, mas a partir do primeiro ano de oferecimento do serviço a quantidade de clientes comece a subir e o servidor comece a obter gargalos, uma reunião do time de negócio com o time técnico é feita e as dores são repassadas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nós estamos tendo reclamações dos clientes, os pagamentos instantâneos estão demorando mais do que o aceitável para serem realizados!&lt;/li&gt;
&lt;li&gt;A plataforma não está se mantendo em pé e isso se agrava deliberadamente nos inícios e finais dos meses, o que pode estar acontecendo?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então, após uma pesquisa técnica mais detalhada a equipe de tecnologia conseguiu encontrar os gargalos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O nosso serviço de &lt;strong&gt;Receipts&lt;/strong&gt; está consumindo muita memória e CPU do servidor e isso se agrava em épocas de pagamento já que a demanda de pagamentos em geral aumenta também os comprovantes e receitas fazendo com que a geração de arquivos seja superior, isso está afetando todo o ecossistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então, após um minuto de silêncio, alguém da sala menciona:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E se aumentássemos a CPU e memória que contratamos no nosso servidor? Acredito que os problemas seriam resolvidos!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa parecia ser uma boa solução, mas alguém apontou:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;De acordo com os dados passados pela equipe de negócios, estamos crescendo em alta velocidade, fora que no próximo mês teremos época de Black Friday. Um aumento agora não serviria de nada pois os custos desse tipo de escalonamento logo iria ficar para trás.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mais um segundo de silêncio, então surgiu outra sugestão:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Podemos então, montar um cluster e colocar o nosso servidor como uma peça instanciável, assim, teremos um load balancer e um escalonamento sob demanda que será mais barato do que o aumento de recursos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A pergunta era: quão barato? E isso foi logo respondido pelo engenheiro de SRE:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na verdade, não compensaria, pois os custos ainda seriam altos visto que uma instância pode atender a uma demanda X, cuja renda prevista mínima seria Y, mas o custo total do FinOps seria Z, trazendo um lucro mínimo e desperdício, visto que vamos estar escalando também serviços desnecessários.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então, após mais algum tempo de pensamento sobre o que era possível fazer, foi sugerida uma conclusão de meio termo que se mostrou viável:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nossos serviços estão bem desacoplados, que tal se mantêssemos nosso servidor como está, mas fizéssemos a abstração de &lt;strong&gt;Receipts&lt;/strong&gt; para um serviço distribuído? A reutilização de código tornaria os custos de um novo repositório quase nulos e dessa forma nós conseguimos escalar o serviço de maneira isolada com uma taxa de desperdício muito menor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Foi então que o time concordou com a solução: era rápida, prática, não alteraria nenhum padrão que já era pré-existente na codebase e permitiria escalonamento virtualmente infinito somente para o que fosse necessário. Perfeito! A solução foi implantada e os resultados se mostraram positivos: a solução como um todo se mostrou estável e robusta. Seguindo a mesma lógica, o serviço &lt;strong&gt;Payments&lt;/strong&gt; logo foi abstraído para ter o seu próprio escalonamento, também com a criação de um cache próprio para não exaurir o banco de dados e a solução agora se via ainda mais rápida e confiável.&lt;/p&gt;

&lt;p&gt;Depois de alguns meses e um crescimento considerável do produto e da empresa, os agentes de negócio contataram mais uma vez o time técnico, dessa vez com dores diferentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O crescimento está ótimo, mas como efeito colateral, nós não conseguimos mais utilizar ferramentas como Excel e PowerBI para acessar os dados de forma sólida e atender nossos clientes de maneira ágil, o que podemos fazer?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Era um caso um pouco mais complexo, de fato a quantidade de dados no banco havia decolado (e muito) e os dados do cache de &lt;strong&gt;Payments&lt;/strong&gt; não eram confiáveis nem suficientes, uma vez que eram simplesmente transacionais e expirava. Após mais uma reunião técnica, foi desvendado um novo caminho para a resolução desse problema: a criação de um &lt;strong&gt;microsserviço&lt;/strong&gt; isolado, isso é, com banco de dados próprio, otimizado para resolver o problema que estava na mesa: análise e depuração de dados. O setup foi montado junto ao time de negócios e um analista de dados foi contratado para desvendar o caminho das pedras, no fim, foi decidido o seguinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um microsserviço isolado seria criado, com seu escalonamento limitado, uma vez que não seria utilizado por uma vasta gama de clientes, mas mantendo sua independência para que não fosse afetado por picos externos na aplicação principal;&lt;/li&gt;
&lt;li&gt;Um banco de dados do estilo &lt;strong&gt;time series&lt;/strong&gt; seria criado para facilitar que os dados pudessem &lt;em&gt;contar uma história&lt;/em&gt; de forma que os agentes de negócio pudessem realizar planejamentos mais coesos e ajudar os clientes de maneira mais assertiva;&lt;/li&gt;
&lt;li&gt;Um pequeno &lt;strong&gt;worker&lt;/strong&gt; (serviço isolado) foi criado para que, de maneira automática, pudesse sincronizar os dados criados no banco de dados com o novo banco de time series, fazendo as adaptações de modelagem necessárias para extrair os melhores insights. Tudo isso com uma disponibilidade de D+1, que no momento é o que o time de negócios precisa para poder atuar de maneira ágil (o suficiente).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E assim vemos os finalmentes, uma arquitetura sólida (para as necessidades do negócio), efêmera (que sempre se altera de acordo com o que for preciso) e híbrida (que não seguirá cegamente um padrão de evolução apenas porque está descrito em algum livro, mas que se importa com nuances e sabe se organizar). &lt;/p&gt;

&lt;h3&gt;
  
  
  Tecnologias e o que utilizar em cada caso
&lt;/h3&gt;

&lt;p&gt;Muitas pessoas têm esse tipo de dúvida, a questão é que não existe uma "receita de bolo" para atuar nesse tipo de caso, até porque é possível que uma decisão tomada de maneira precipitada acabe prejudicando o sistema como um todo de uma maneira quase irreversível. A chave aqui é a comunicação, se você estiver em um lugar que valoriza experiências acima de certificações, conversar, fazer reuniões e papos técnicos é o melhor caminho. Afinal, entender do seu Cláudio da arquitetura que se lembra do fatídico incidente em 2009 onde uma implementação incerta quebrou a produção causando 300.000 dólares de prejuízo em vendas e foi resolvida de maneira calma, com um post-mortem coeso é melhor do que levar em consideração uma decisão tomada em 15 minutos totalmente enviesada do Adriano da engenharia que tem 3 certificações AWS e 2 certificações Azure, mas nunca participou de um war room nem colocou nada significante em produção. (Nomes e situações completamente fictícios)&lt;/p&gt;

&lt;p&gt;No mais, existe um post no meu LinkedIn que não se relaciona diretamente com o assunto mas pode te dar insights valiosos sobre como tomar esse tipo de decisão. Veja &lt;a href="https://www.linkedin.com/posts/scarletrose_vejo-muitas-pessoas-principalmente-iniciantes-activity-7282705130762723328-6kvJ?ut" rel="noopener noreferrer"&gt;aqui&lt;/a&gt; e até a próxima!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ah e se você estiver se perguntando sobre eu não ter mencionado "o que é um pod e um container", ou algo como "utilize o EKS da seguinte maneira", o motivo é claro: nesse artigo, busquei utilizar da linguagem genérica a minha força, afinal, para cada solução existem N problemas e como eu sempre digo, não existe bala de prata. Mesmo assim, buscarei abordar assuntos mais nichados em artigos futuros.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>[pt-BR] Não negligencie logs na sua solução</title>
      <dc:creator>Scarlet Rose</dc:creator>
      <pubDate>Fri, 13 Sep 2024 01:17:16 +0000</pubDate>
      <link>https://dev.to/scarlet/pt-br-nao-negligencie-logs-na-sua-solucao-12e2</link>
      <guid>https://dev.to/scarlet/pt-br-nao-negligencie-logs-na-sua-solucao-12e2</guid>
      <description>&lt;p&gt;Em um belo dia, você está trabalhando normalmente quando de repente recebe um chamado: um gateway de APIs crítico para o negócio está apresentando intermitências e os usuários estão com dificuldades para acessar serviços chave que determinam a produtividade da sua empresa como um todo. Até aí tudo bem - você junta os responsáveis pelo gateway, abre uma war room rotineira para identificar o problema e começa pela forma mais simples de identificar o problema: os logs.&lt;/p&gt;

&lt;p&gt;Nos primeiros minutos, após abrir o Splunk, Dynatrace, AWS Cloudwatch ou o que quer que esteja sendo utilizado para logs - você percebe que não aparece nada de errado. O logging não está sendo realizado de maneira correta, sendo utilizado apenas em situações onde operações começam e terminam, mas quase nunca para erros - e pior, quando os erros estouram no logs, apenas o título (conhecido como "Message" em muitas linguagens) é exposto e não dá nenhuma pista real do que está acontecendo, se provando completamente inúteis e apenas ofuscando ainda mais o conteúdo da lista de logs em produção.&lt;/p&gt;

&lt;p&gt;Próximo passo: vamos utilizar a nossa ferramenta de observabilidade para entender melhor como os requests estão se comportando? Após alguns outros minutos explorando, você e sua equipe percebem que a maioria dos erros é 500 - perfeito: agora nós iremos conseguir entender os motivos desse erro e resolver esse problema de uma vez por toda, certo? Errado. A gateway, especificamente as APIs internas que estão dando problema, está retornando apenas um status code 500 e isso nos remete a uma situação intrigante - antigamente os erros 500 eram estourados com uma stack trace completa na cara do usuário, mas isso foi identificado como prejudicial pela equipe de desenvolvimento, que fez com que os erros 500 não retornassem mais nada ao invés de identificar o problema e dinamicamente construir uma mensagem de erro que faça sentido para a situação - ou mesmo fazer o log corretamente, o que também seria uma opçãok, inclusive, a mais adequada.&lt;/p&gt;

&lt;p&gt;Agora, o que resta para a sua equipe é simplesmente subir uma alteração de emergência que ainda não vai resolver o problema - uma melhoria na qualidade dos logs, atrasada porém necessária, que vai - prontamente - providenciar à equipe de desenvolvimento todas as informações necessárias para identificar o problema. Fazendo a subida - que provavelmente vai custar mais um dia de intermitências para os usuários - agora é necessário esperar para que os usuários tentem acessar novamente (e recebam as mensagens de erro, caso elas existam - pois o próprio restart da aplicação após as atualizações pode fazer os erros sumirem magicamente - quem nunca?). Com os logs agora populados com mensagens de erro significativas, é hora te começar a trabalhar no que realmente importa: a solução do problema.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>[pt-BR] Padrões de código em diferentes empresas - o que devo usar?</title>
      <dc:creator>Scarlet Rose</dc:creator>
      <pubDate>Fri, 23 Aug 2024 21:57:37 +0000</pubDate>
      <link>https://dev.to/scarlet/padroes-de-codigo-em-diferentes-empresas-o-que-devo-usar-7a</link>
      <guid>https://dev.to/scarlet/padroes-de-codigo-em-diferentes-empresas-o-que-devo-usar-7a</guid>
      <description>&lt;p&gt;No mundo da programação, é muito comum que existam convenções e regras de estilização específicas para que a ordem seja mantida durante a criação de soluções dos mais variados tipos. Geralmente, essas convenções são criadas a partir das ideias iniciais de design previamente&lt;br&gt;
desenvolvidas para aquela linguagem, fazendo com que todo código criado naquela tecnologia siga um padrão específico. Um grande exemplo que percebi ao longo da minha carreira foi o conjunto de regras que existe no C#, a linguagem C-like da Microsoft desenvolvida para rodar no runtime .NET (muito similar a Java, por sinal, inclusive em algumas convenções específicas). &lt;/p&gt;

&lt;p&gt;Por exemplo, no C#, a nomeação de classes, propriedades públicas e métodos (não irei me aprofundar sobre o que são nesse artigo em específico) é por convenção realizada em &lt;strong&gt;PascalCase&lt;/strong&gt; - um casing onde as palavras são separadas por uma letra maiúscula (similar ao &lt;strong&gt;camelCase&lt;/strong&gt;, onde a primeira letra do casing é minúscula, e a separação das outras letras ocorre com letras maiúsculas indefinidamente). Mesmo assim, em diferentes empresas que trabalhei com .NET (e outras linguagens também, mas vamos focar no .NET por agora), existe a utilização de padrões de código que vão contra essas convenções, inclusive em alguns lugares foram criados sistemas de regras inteiros para ditar como devem ser os padrões a serem seguidos devido a decisões e necessidades internas. &lt;/p&gt;

&lt;p&gt;Um grande exemplo onde convenções se adaptam melhor se direcionadas às necessidades do negócio, é por exemplo, uma empresa que utiliza diversas tecnologias para montar uma mesma solução - visto a presença de times multidisciplinares, peças da solução que se adaptam melhor a tecnologias específicas ou limitações de negócio que fazem com que certas partes da solução tenham que ser construídas com essas tecnologias. Leve em consideração uma empresa hipotética que utilize &lt;strong&gt;lambdas python&lt;/strong&gt;, que depois de diversas análises técnicas por parte de times de engenharia e arquitetura se mostraram a forma mais rápida e efetiva de prototipar e montar peças de solução. A mesma empresa conta com uma vasta gama de desenvolvedores C#, fazendo com que várias soluções (como workers e REST APIs) sejam feitas utilizando a linguagem, e por isso uma solução interessante para se manter no padrão entre comunicações fosse simplesmente alterar o casing das respostas de APIs e outras requisições para &lt;strong&gt;snake_case&lt;/strong&gt;, beneficiando assim a utilização de python no ambiente de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Quando se fala de padrões de código, também podem ser levados em consideração conjuntos de práticas que são realizadas para montar um programa. O melhor exemplo para falar sobre conjuntos de práticas é o JavaScript (ou TypeScript), sendo uma linguagem extremamente flexível onde é possível utilizar diversos paradigmas diferentes em uma mesma aplicação. Por exemplo, algumas empresas utilizam o framework &lt;strong&gt;NestJS&lt;/strong&gt; para o desenvolvimento de aplicações web, esse framework é extremamente baseado em programação orientada a objetos - que por sua vez conta com vasta utilização de classes, herança assim como vários design patterns, onde o que mais se destaca é a injeção de dependências.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Injeção de dependência (Dependency Injection, em inglês) é um padrão de desenvolvimento de programas de computadores utilizado quando é necessário manter baixo o nível de acoplamento entre diferentes módulos de um sistema. Nesta solução as dependências entre os módulos não são definidas programaticamente, mas sim pela configuração de uma infraestrutura de software (container) que é responsável por "injetar" em cada componente suas dependências declaradas. - &lt;em&gt;Wikipedia&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Geralmente, as soluções montadas em Nest utilizam um pattern de serviços para identificar peças de funcionalidades que podem ser reutilizadas de maneira desacoplada, como no exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./interfaces/cat.interface&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;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CatsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já outras empresas utilizam uma arquitetura mais livre, geralmente baseada em módulos e métodos ou até mesmo "features", passando as dependências como argumentos nas funcionalidades que irão precisar fazer seu uso, fazendo assim com que a utilização desses métodos também seja possível em ambientes de testes e outras ocasiões. Um exemplo, diretamente de um projeto pessoal que fiz anteriormente, pode ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createPendingMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreatePendingMessageOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sentAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkJwtOwnership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;senderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pendingMessageTable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;sentAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;senderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;senderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;receiverId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receiverId&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;input&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mas afinal, o que utilizar?
&lt;/h2&gt;

&lt;p&gt;Do ponto de vista profissional, se adequar ao ambiente de trabalho é uma soft skill essencial para "sobreviver". Obviamente não estou falando de aceitar decisões ruins sem questionamento, mas sim para buscar entender o motivo de certas decisões serem implementadas e de onde elas vieram, só assim é possível acumular experiência para poder confrontar decisões de design futuras. O correto é sempre procurar se adaptar ao design utilizado por sua equipe ou empresa, e se cabível, questionar e implementar gradualmente mudanças dependendo do seu nível de influência. Isso não significa que fora do ambiente de trabalho seja necessário utilizar essas mesmas decisões de design, afinal, uma das características de uma boa pessoa programadora é a adaptabilidade.&lt;/p&gt;




&lt;p&gt;Gostou do artigo? Tem sugestões ou críticas? Me acompanhe no meu &lt;a href="https://github.com/somecodingwitch" rel="noopener noreferrer"&gt;Github&lt;/a&gt; ou &lt;a href="https://x.com/scarletrosedev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ux</category>
      <category>career</category>
      <category>beginners</category>
    </item>
    <item>
      <title>[en-US] Managing feedback cycles in a tech startup</title>
      <dc:creator>Scarlet Rose</dc:creator>
      <pubDate>Tue, 23 Jan 2024 04:59:37 +0000</pubDate>
      <link>https://dev.to/scarlet/managing-feedback-cycles-in-a-tech-startup-5c00</link>
      <guid>https://dev.to/scarlet/managing-feedback-cycles-in-a-tech-startup-5c00</guid>
      <description>&lt;p&gt;Feedback cycles are a important part of every successful tech startup environment. They are responsible for rapidly gathering information about how the things are going, how they could be and if something is not ideal for the current product. In early-stage startups feedbacks can be the key to create a great product and keep customers and a good feedback cycle is directly related to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a feedback cycle?
&lt;/h2&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%2F3ugjw1xpowd7552yft96.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%2F3ugjw1xpowd7552yft96.png" alt="Feedback cycle as a diagram, where it starts by the situation and scales to feedback, then reflection" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A feedback cycle is a repeatable scheme of consistency that is focused on gather feedback based on implementations. It can be measured using the, commonly used in interviews, STARR method (Situation, Task, Action, Result and Reflection). That cycle starts every time a new implementations is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Situation
&lt;/h2&gt;

&lt;p&gt;Firstly, we have a situation. It can be the need for a bug fix or the desire for a new feature and this information usually comes from the client. A situation is the first step to start aggregating information about how the problems needs to be solved - even if they are not even started to be worked on yet. The key topics here are: "why do we need this implementation?" and "which events could be the cause for that situation to be happening now?".&lt;/p&gt;

&lt;h2&gt;
  
  
  Task
&lt;/h2&gt;

&lt;p&gt;After the situation, the next step is to write an action plan that here is most commonly called "Task", that is the actual work force to make the desired changes in the product. The definition of task is pretty simple, every planning about the effort that you make to create something new or solve an existing problem can be considered a task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Action
&lt;/h2&gt;

&lt;p&gt;Despite bein a self-explanatory one, an action, besides being the execution of the task itself is a step that should be carefully handled. An action can not be executed without a task, and a task can not be redacted without a situation. A lot of startups tries to solve inexistent problems, creating tasks without situations, or even try to execute actions skipping the task step, leading to bad product development that can be bad code, bugs, unexpected problems, subcoverage of situations and much more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;The majority of the startups fails on properly organizing results. Fetching and sorting results can be meaningful to discover insights that haven't been caught by anyone yet. With the results it is possible to see points of failure, possible previously unexpected situations, hidden test cases and even product possibilities that haven't been explored yet and are an actual need to be brought to the market. Results are also very important to give meaning to the next step, the &lt;em&gt;feedback&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;Feedbacks are the key to improvement, not only as a single person, but to entire teams or even entire companies. Feedbacks are the collective vision of the cycle as an entire entity, they will provide each participant's opinion on each step since the situation to the result, providing the insights previously mentioned in an easy-to-hear way, suggestions and more concise descriptions to power up the product development process. Feedbacks can provided from both the client and all the collaborators of a tech startup and should be always taken in consideration, from the trainee to the most important specialist developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflection
&lt;/h2&gt;

&lt;p&gt;Reflecting about what was made in the past is the best way to avoid errors, not only the explicit ones but also the missed opportunities to make something great. Reflection sessions, even the asynchronous ones - through text -, are very important to decide the improvement points based on the past. Most of the reflection sessions will be "blank" in the beginning until the team get used to talk more comfortably about their own mistakes, strengths and how they actually work and that's normal, it's not a step that can be achieved so easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Luca Mezzalira similar approach
&lt;/h2&gt;

&lt;p&gt;Luca Mezzalira, the author of the books &lt;a href="https://www.buildingmicrofrontends.com/" rel="noopener noreferrer"&gt;Building Microfrontends&lt;/a&gt; and &lt;a href="//www.apress.com/gb/book/9781484231791"&gt;Front-End Reactive Architectures&lt;/a&gt; reaches a similar approach using the "PDCA" cycle: "plan, do, check, act" where he talks about a proper feedback cycle based on concrete plans that are constantly checked during the repetition of the cycle.&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%2Fe3i95vvlmaxfbumknevy.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%2Fe3i95vvlmaxfbumknevy.png" alt="PDCA Process diagram" width="800" height="473"&gt;&lt;/a&gt;&lt;br&gt;
Diagram source: &lt;a href="http://upload.wikimedia.org/wikipedia/commons/a/a8/PDCA_Process.png" rel="noopener noreferrer"&gt;http://upload.wikimedia.org/wikipedia/commons/a/a8/PDCA_Process.png&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;He also explains direct relationship with various topics such as test driven development, static analysis, pair programming, dailies, pair programming and many others. You can see his complete article &lt;a href="https://lucamezzalira.com/2015/06/14/the-power-of-feedback-loops/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of feedback
&lt;/h2&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%2Fvabzdnwkuhosbbo5tef6.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%2Fvabzdnwkuhosbbo5tef6.png" alt="Feedback types diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Diagram source: &lt;a href="https://www.collidu.com/presentation-types-of-feedback" rel="noopener noreferrer"&gt;https://www.collidu.com/presentation-types-of-feedback&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are four types of feedback: positive, negative, correcting and motivating. As a tech manager you should avoid both negative and motivating ones. Why? - It is simple, negative feedbacks won't provide constructive information about on how the receiver can self improve, it is more like a punishment. Motivating feedbacks can appear good at the first time, but they can lock the receiver in a comfort zone causing the contrary effect to self improvement and putting the team in a risky situation.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>management</category>
      <category>feedback</category>
      <category>productivity</category>
    </item>
    <item>
      <title>[en-US] What should go on my test code?</title>
      <dc:creator>Scarlet Rose</dc:creator>
      <pubDate>Tue, 09 Jan 2024 01:30:32 +0000</pubDate>
      <link>https://dev.to/scarlet/what-should-go-on-my-test-code-4de7</link>
      <guid>https://dev.to/scarlet/what-should-go-on-my-test-code-4de7</guid>
      <description>&lt;p&gt;What should go on my test code? Unlike we think, it is a common question among the developers - main the newcomers - that advendure themselves in the world of programming. To start talking about this topic, some questions need to be answered and one of them is: "what are tests and why are they so important?". Tests are not only pieces of code responsible for ensuring a behavior in your main codebase, they tell you a story, they are responsible for teaching you things about your just-finished code that you did not even know. &lt;/p&gt;

&lt;p&gt;But... Why does all these fine words mean? Basically, they tell you that tests are not exactly focused on ensuring behaviors that are already expected but the ones that we are not really expecting, and this is a really hard task that requires not only technical knowledge, but &lt;em&gt;business&lt;/em&gt; knowledge about what you are doing. Tests are not meant to verify the basic, check database connections correctness or even validate classes and methods, their real and glorious objective is to ensure that - technically - your application mets all the requirements to be reliable to execute your &lt;em&gt;business rules&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The main responsibility of a test is to track and ensure consistent behaviors that composes the pipeline to execute your business rules in a reliable way with meaningful causes and effects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Meaningful causes and effects
&lt;/h2&gt;

&lt;p&gt;Every effect will have a cause - and this does not change in the context of your application. Look at your final users as unpredictable sources of different causes that will end on different effects. Create your tests based on that concept, try to explore and select ways that your users have to possibly break your application. Also learn from past mistakes, creating tests that are responsible for trying to reproduce previous bugs and may fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thinking on resilience and reliability
&lt;/h2&gt;

&lt;p&gt;In the most basic meaning of the words that can fit for that context, we can identify "reliability" as the capability of your system to survive to expected causes such as power outages, denial of service attacks, cloud outages and environmental causes that usually happens time to time. But the main challenge of any development team is to ensure resilience - the capacity to handle unexpected problems - I mean - the capacity to handle problems like invasion attempts, unprompted system breaks and other random problem. This kind of capacity is not directly related to "how should I solve that problem automatically?" and more like to: "what should I do to avoid that compromised part breaking the rest of the system? how can I properly isolate my current problem and also gather sufficient information that will be sent to my logs to future troubleshoot?".&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Testing can be tricky. Testing don't work only as a way to "see if something else is breaking", but a direct tool to act as a truth source during a project development. Tests are meant to be meaningful, to ensure resilience and make sure your project is following consistent patterns in order to attend your customers in the most profitable way.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
