<?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: Matheus Morett</title>
    <description>The latest articles on DEV Community by Matheus Morett (@madmorett).</description>
    <link>https://dev.to/madmorett</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1153518%2F819e3830-8c92-493e-ab44-10c334a1c96a.png</url>
      <title>DEV Community: Matheus Morett</title>
      <link>https://dev.to/madmorett</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/madmorett"/>
    <language>en</language>
    <item>
      <title>Redis is the ceiling: why I built bullmq-outbox</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 20 Sep 2026 14:42:56 +0000</pubDate>
      <link>https://dev.to/madmorett/redis-is-the-ceiling-why-i-built-bullmq-outbox-3llj</link>
      <guid>https://dev.to/madmorett/redis-is-the-ceiling-why-i-built-bullmq-outbox-3llj</guid>
      <description>&lt;p&gt;In April 2025 I went out for a barbecue lunch. I came back, opened the dashboard, and something had degraded in production.&lt;/p&gt;

&lt;p&gt;I am the CTO of &lt;a href="https://monest.com.br" rel="noopener noreferrer"&gt;Monest&lt;/a&gt;, a debt collection company built on AI. The shape of our business is simple. A debtor sends a message saying they want to negotiate, we queue it, an agent drafts a response, we reply. Messages come in through a webhook. Everything after the webhook is BullMQ.&lt;/p&gt;

&lt;p&gt;That afternoon we were processing messages far slower than they were arriving. The queue backed up. Waiting jobs piled up in Redis. And Redis filled.&lt;/p&gt;

&lt;p&gt;A full Redis does not slow down. It refuses. &lt;code&gt;queue.add()&lt;/code&gt; rejected, the webhook returned an error, and the message was gone. Not delayed. Gone. There was nothing to retry, because nothing had ever been written down.&lt;/p&gt;

&lt;p&gt;We were losing negotiations. That is the part that matters. We were not dropping jobs. We were dropping people who were trying to pay us.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flaw is not a bug
&lt;/h2&gt;

&lt;p&gt;I like BullMQ a lot. We run it in production and we are not moving off it. But it has one property you have to design around.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redis is the ceiling.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every job you have not processed yet lives in RAM. Your backlog and your memory limit are the same number. So anything that widens the gap between arrival rate and processing rate walks you toward that limit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A slow downstream dependency. Consumers get slower, &lt;code&gt;waiting&lt;/code&gt; grows, memory grows.&lt;/li&gt;
&lt;li&gt;One oversized payload. Someone ships a job carrying a whole document instead of an id, and a queue that used to cost kilobytes now costs megabytes.&lt;/li&gt;
&lt;li&gt;A traffic spike you did not plan for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Payload guards catch the cases you thought of. Alerts tell you after &lt;code&gt;waiting&lt;/code&gt; is already large, which is exactly when you have the fewest options.&lt;/p&gt;

&lt;p&gt;And the obvious answer, "put it on a cluster", does not do what people assume it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redis Cluster does not split a queue
&lt;/h2&gt;

&lt;p&gt;This is worth spelling out, because it is the most common reply to this problem and it is wrong in a specific way.&lt;/p&gt;

&lt;p&gt;BullMQ lays a queue out as a set of keys sharing one qualified name: &lt;code&gt;bull:orders:wait&lt;/code&gt;, &lt;code&gt;bull:orders:meta&lt;/code&gt;, &lt;code&gt;bull:orders:id&lt;/code&gt;, &lt;code&gt;bull:orders:&amp;lt;jobId&amp;gt;&lt;/code&gt;, and so on. Its operations are Lua scripts, and a single &lt;code&gt;add&lt;/code&gt; touches several of those keys at once. The wait list, the counter, the job hash, the marker.&lt;/p&gt;

&lt;p&gt;In Redis Cluster, a Lua script may only touch keys that live in the same hash slot. So every BullMQ-on-Cluster setup gives the queue a hash tag. You name it &lt;code&gt;{orders}&lt;/code&gt; instead of &lt;code&gt;orders&lt;/code&gt;, which forces all of its keys onto one slot.&lt;/p&gt;

&lt;p&gt;That is what makes it work. It is also what caps it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A hash slot is not divisible.&lt;/strong&gt; It lives on exactly one node, in that node's memory. So Cluster distributes &lt;em&gt;queues&lt;/em&gt; across nodes. It never distributes &lt;em&gt;one queue&lt;/em&gt; across nodes.&lt;/p&gt;

&lt;p&gt;The consequence is not that you have a bigger ceiling. It is that you have several smaller ones, and a queue is bound to whichever one it landed on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The limit for a queue is the memory of the single node holding its slot, not the memory of the cluster.&lt;/li&gt;
&lt;li&gt;One hot queue can fill its node while the rest of the cluster sits nearly empty. The cluster is fine. Your queue is not.&lt;/li&gt;
&lt;li&gt;Adding nodes does not help the queue that is in trouble. Resharding moves whole slots. It cannot move half of one, so the queue lands somewhere else, intact, with the same problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cluster raises your total capacity and changes nothing about the failure you actually hit. The ceiling for any given queue is still a single machine's RAM. When you reach it, the enqueue fails and the job disappears, because the queue is the only place that job ever existed.&lt;/p&gt;

&lt;p&gt;That is the part worth fixing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built that afternoon
&lt;/h2&gt;

&lt;p&gt;The fix is old and boring, which is why it works. An &lt;strong&gt;outbox&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the write to the queue fails, write the job somewhere else, somewhere with a different failure domain, and put it back when the queue recovers.&lt;/p&gt;

&lt;p&gt;I wrapped our queues so that every &lt;code&gt;add()&lt;/code&gt; had a &lt;code&gt;catch&lt;/code&gt;. On failure, the job went to DynamoDB: queue name, job name, payload, options, status &lt;code&gt;PENDING&lt;/code&gt;. A cron ran every 15 minutes, read the pending rows, and re-enqueued them through the real queue.&lt;/p&gt;

&lt;p&gt;Three details decided whether this actually worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The original error is still thrown.&lt;/strong&gt; The outbox buys you a replay, not a lie. The caller still finds out the enqueue failed and still decides what to tell the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job options are preserved.&lt;/strong&gt; &lt;code&gt;jobId&lt;/code&gt;, &lt;code&gt;attempts&lt;/code&gt;, &lt;code&gt;backoff&lt;/code&gt;, all serialized and restored on replay. Without &lt;code&gt;jobId&lt;/code&gt;, replay is not idempotent and you trade lost jobs for duplicated ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The recovery loop does not share the failure it is recovering from.&lt;/strong&gt; This is the one people get wrong. Our scheduler runs on a separate, dedicated Redis. A drain loop living inside the Redis that just died never fires, and you find out on Monday.&lt;/p&gt;

&lt;p&gt;One more thing, learned the hard way. Set &lt;code&gt;reserved-memory-percent&lt;/code&gt; on your Redis parameter group. A Redis at 100% of &lt;code&gt;maxmemory&lt;/code&gt; does not fail cleanly. It hangs, and BullMQ hangs with it, because &lt;code&gt;maxRetriesPerRequest: null&lt;/code&gt; is required by the framework and ioredis will retry forever. Reserving a slice makes the OOM arrive as an error you can actually catch. An outbox that never receives an error is not an outbox.&lt;/p&gt;

&lt;p&gt;Also, not every queue should be captured. We excluded the real-time conversation queues. A chat turn replayed fifteen minutes later is worse than one never sent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then it paid for itself
&lt;/h2&gt;

&lt;p&gt;Some time later, a regression shipped. One specific queue started writing payloads larger than planned, past the payload guards we already had. Those guards existed. It happened anyway.&lt;/p&gt;

&lt;p&gt;The Redis backing that queue hit its limit again.&lt;/p&gt;

&lt;p&gt;And nothing happened.&lt;/p&gt;

&lt;p&gt;Everything that failed to enqueue went to DynamoDB. The cron picked it up and replayed it. No lost jobs, no lost negotiations, no incident call.&lt;/p&gt;

&lt;p&gt;The difference between April and that day was not that we had gotten better at preventing a full Redis. We had not. The difference was that hitting the ceiling stopped being a data-loss event and became a latency event.&lt;/p&gt;

&lt;p&gt;That is the whole argument. You will not prevent every one of these. You can decide what one costs you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it is a package now
&lt;/h2&gt;

&lt;p&gt;The Monest version was tied to things you do not have: NestJS, DynamoDB, our module structure. So I rewrote it as &lt;a href="https://github.com/madmorett/bullmq-outbox" rel="noopener noreferrer"&gt;&lt;strong&gt;bullmq-outbox&lt;/strong&gt;&lt;/a&gt;.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createOutbox&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;bullmq-outbox&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;Queue&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;bullmq&lt;/span&gt;&lt;span class="dl"&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;outbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createOutbox&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myStore&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;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrapQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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;emails&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Behaves exactly like the queue you passed in, until Redis says no.&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;welcome&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="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then drain from somewhere with its own failure domain:&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;outbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// { requeued: 12, failed: 0, skipped: 3, expired: 0 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design decisions worth stating, because they are the opinionated part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero dependencies. It does not even import &lt;code&gt;bullmq&lt;/code&gt;.&lt;/strong&gt; The wrapper is structural, so v5, v6 and BullMQ Pro all work from one build. &lt;code&gt;wrapQueue&lt;/code&gt; is a Proxy, not a subclass, for the same reason: groups, batches and every other method pass straight through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No storage adapters ship with it.&lt;/strong&gt; Your outbox belongs in a database you already operate and already back up. You write four functions: &lt;code&gt;save&lt;/code&gt;, &lt;code&gt;loadPending&lt;/code&gt;, &lt;code&gt;markProcessed&lt;/code&gt;, &lt;code&gt;markFailed&lt;/code&gt;. Working Postgres, Redis, MongoDB and DynamoDB implementations live in &lt;code&gt;examples/&lt;/code&gt; as files to copy, each with its schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is not a broker.&lt;/strong&gt; Redis stays the queue. This is a fallback, and it should stay boring.&lt;/p&gt;

&lt;p&gt;The integration tests break a real Redis for real. &lt;code&gt;maxmemory&lt;/code&gt; is set just above current usage, so writes are rejected with the same &lt;code&gt;OOM command not allowed&lt;/code&gt; error ElastiCache throws. A fake queue can prove the logic. It cannot prove the package survives the thing it exists for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number to watch
&lt;/h2&gt;

&lt;p&gt;Not the count of replayed jobs. The &lt;strong&gt;age&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;onJobRequeued&lt;/code&gt; gives you &lt;code&gt;ageMs&lt;/code&gt;, how long that job sat in the outbox before it made it back. That is your real recovery time, and it is the number that tells you whether the fallback is working or quietly filling up. A count of 40 tells you nothing. Forty jobs with an average age of four hours tells you your drain is broken.&lt;/p&gt;

&lt;p&gt;Which, of course, is easier to see when you can actually see your queues. If you want the best tool on the market to watch BullMQ jobs, use &lt;a href="https://bullpane.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Bullpane&lt;/strong&gt;&lt;/a&gt;. Self-hosted.&lt;/p&gt;




&lt;p&gt;&lt;code&gt;npm install bullmq-outbox&lt;/code&gt; · &lt;a href="https://github.com/madmorett/bullmq-outbox" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you fan one event out to many queues, &lt;a href="https://github.com/madmorett/bullmq-fanout" rel="noopener noreferrer"&gt;&lt;strong&gt;bullmq-fanout&lt;/strong&gt;&lt;/a&gt; composes with it. Wrap your queues first and the fan-out inherits the durability.&lt;/p&gt;

</description>
      <category>bullmq</category>
      <category>node</category>
      <category>nestjs</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Talk is cheap: high-agency e a técnica do 1-3-1</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sat, 08 Aug 2026 13:54:41 +0000</pubDate>
      <link>https://dev.to/madmorett/talk-is-cheap-high-agency-e-a-tecnica-do-1-3-1-15em</link>
      <guid>https://dev.to/madmorett/talk-is-cheap-high-agency-e-a-tecnica-do-1-3-1-15em</guid>
      <description>&lt;p&gt;Desde o início da minha carreira eu sempre fui uma pessoa muito ambiciosa. No dia 1 do meu primeiro emprego eu já entrava na empresa pensando: &lt;em&gt;o que funciona bem aqui, o que não funciona, e como eu posso me destacar?&lt;/em&gt; Aquela proatividade clássica de estagiário que quer vencer na vida.&lt;/p&gt;

&lt;p&gt;O problema é que, conforme o tempo foi passando, eu percebi uma coisa desconfortável: eu era muito mais um &lt;strong&gt;reclamão&lt;/strong&gt; do que um &lt;strong&gt;resolvedor de problemas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Até que um dia eu ouvi do meu chefe:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Talk is cheap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  O que eu não estava enxergando
&lt;/h2&gt;

&lt;p&gt;Eu conseguia ver mil ineficiências na empresa. E minha visão afunilada só sabia produzir um pensamento: &lt;em&gt;"meu Deus, vou reclamar, não é possível que ninguém vê isso"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Hoje, na posição em que estou, liderando uma área de tecnologia com mais de 50 pessoas, eu sei exatamente o motivo de ninguém estar "vendo".&lt;/p&gt;

&lt;p&gt;Todo mundo via. Só não era prioridade.&lt;/p&gt;

&lt;p&gt;Você não consegue garantir eficiência máxima em tudo ao mesmo tempo. Você precisa &lt;strong&gt;escolher as batalhas que vai comprar&lt;/strong&gt;. No fim, o que interessa é o DRE mostrando resultado positivo, margem controlada, custo sob controle. E, na fila de prioridades, aquela ineficiência que o Matheus estagiário e o Matheus júnior enxergavam era pouco relevante diante do cenário macro.&lt;/p&gt;

&lt;p&gt;Isso não significa que ela não era importante. Significa que, diante de todos os problemas que uma diretoria precisa resolver, aquele não era o prioritário &lt;strong&gt;naquele momento&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;E aqui está a virada de chave: a diretoria não precisava de mais alguém apontando o problema. Precisava de alguém disposto a resolvê-lo sem consumir a atenção dela.&lt;/p&gt;

&lt;p&gt;Quando eu ouvi "talk is cheap" do meu CEO, a mensagem era clara: &lt;em&gt;você reclamar disso toda semana comigo não vai mudar nada. Você pensar e aplicar uma solução é o que vale.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hoje, mesmo ocupando a liderança máxima de tecnologia, eu preciso tomar o mesmo cuidado — não floodar o CEO com reclamações inúteis. E pra isso eu mantenho duas técnicas sempre na cabeça.&lt;/p&gt;

&lt;h2&gt;
  
  
  Técnica 1: o 1-3-1
&lt;/h2&gt;

&lt;p&gt;Em vez de chegar reclamando de alguma coisa, você chega com:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1 problema&lt;/strong&gt; — claro, com impacto mensurável&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3 possíveis soluções&lt;/strong&gt; — com trade-offs honestos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 recomendação&lt;/strong&gt; — qual você executaria agora, com as informações e condições que você tem&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fui4f3c9idsgj124lfdlv.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fui4f3c9idsgj124lfdlv.png" alt="Tecnica 1-3-1" width="799" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O efeito disso na cabeça de quem te ouve é enorme. Você deixa de soar como &lt;em&gt;"tem um problema, resolve pra mim"&lt;/em&gt; e passa a soar como:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Estou vendo um problema, mas pode ficar tranquilo com as suas prioridades, porque eu já pensei e vou executar uma solução. Você concorda com a direção?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hoje, atuando como diretor, isso é música pros meus ouvidos. E, com certeza, essa pessoa fica marcada na minha cabeça quando aparece uma vaga de liderança ou uma área nova pra alguém assumir.&lt;/p&gt;

&lt;h3&gt;
  
  
  Um exemplo concreto
&lt;/h3&gt;

&lt;p&gt;Ruim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Nosso pipeline de CI tá insuportável, demora 40 minutos, ninguém aguenta mais."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;1-3-1:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Problema:&lt;/strong&gt; o CI leva 40min por PR. Com ~60 PRs/semana, isso são ~40h de espera por semana no time, e a galera parou de rodar a suíte localmente porque virou hábito "deixa o CI pegar".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opções:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Paralelizar a suíte em 4 workers — corta pra ~12min, custo de runner sobe ~R$ 800/mês, 2 dias de trabalho.&lt;/li&gt;
&lt;li&gt;Rodar só os testes afetados por diff no PR e a suíte completa no merge — corta pra ~6min, mas exige mapeamento de dependências e tem risco de falso negativo.&lt;/li&gt;
&lt;li&gt;Subir a máquina do runner — corta pra ~25min, custo sobe ~R$ 1.500/mês, meio dia de trabalho.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Recomendação:&lt;/strong&gt; opção 1. Melhor relação ganho/risco, reversível, e não depende de refactor. Começo quinta se não houver objeção.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A segunda versão não é mais longa por capricho. Ela transfere o trabalho cognitivo de quem decide pra quem propõe, que é exatamente o ponto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Técnica 2: cultura high-agency
&lt;/h2&gt;

&lt;p&gt;A outra coisa que me ajudou muito foi entender a &lt;strong&gt;pirâmide de high-agency&lt;/strong&gt; e onde eu estava nela.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fahgftleu6163hsqkuzoh.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fahgftleu6163hsqkuzoh.png" alt="Pirâmide High-Agency" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do chão pro topo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Espera mandarem.&lt;/strong&gt; Executa quando pedem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pergunta o que fazer.&lt;/strong&gt; Identifica que tem algo errado e devolve a decisão.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recomenda e espera aprovação.&lt;/strong&gt; Aqui mora o 1-3-1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Age e reporta imediatamente.&lt;/strong&gt; Decide, executa, comunica na sequência.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owner.&lt;/strong&gt; Age dentro do seu domínio e reporta na cadência normal, porque a confiança já está estabelecida.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O topo da pirâmide é o &lt;strong&gt;owner&lt;/strong&gt;: a pessoa que age e depois reporta qual foi a ação e o resultado. É um passo mais arrojado que o 1-3-1, e tem muito mais valor, mas só funciona se a sua empresa de fato empodera uma cultura de &lt;em&gt;"peça desculpas, não permissão"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Se sua empresa tem essa cultura, é definitivamente o que eu recomendo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como escolher entre 1-3-1 e owner
&lt;/h3&gt;

&lt;p&gt;A régua que eu uso é simples: &lt;strong&gt;qual o custo de estar errado?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Porta de duas mãos&lt;/strong&gt; (reversível — feature flag, refactor interno, mudança de processo do squad): aja. Reporte depois. Nível 4 ou 5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Porta de uma mão&lt;/strong&gt; (difícil ou caro de desfazer — migração de banco, contrato, mudança que impacta cliente, decisão de arquitetura estrutural): use 1-3-1. Alinhe antes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confundir os dois é o erro mais comum dos dois lados. Gente sênior pedindo permissão pra coisa reversível trava o time. Gente agindo sozinha em porta de uma mão gera incidente.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que isso muda quando você está do outro lado da mesa
&lt;/h2&gt;

&lt;p&gt;Aqui é onde a coisa fica interessante pra quem lidera.&lt;/p&gt;

&lt;p&gt;Se você é diretor ou liderança, isso muda &lt;strong&gt;como você desenha a burocracia da sua empresa&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A diretoria nunca vai ter olhos pra tudo. E uma ineficiência que parece irrelevante lá de cima pode ser um baita gargalo pra operação no dia a dia. Então qual é o pior papel que você pode assumir?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ser o gargalo que impede pessoas high-agency de brilhar.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se toda melhoria precisa passar por você, você acabou de transformar o seu calendário no teto de crescimento da empresa. As pessoas boas vão tentar duas ou três vezes, esbarrar na fila de aprovação, e voltar pro nível 1 da pirâmide. Aí você olha o time e pensa "por que ninguém toma iniciativa aqui?".&lt;/p&gt;

&lt;p&gt;Criar uma cultura com &lt;strong&gt;controles de qualidade, mas sem burocracia que desencoraje a ação&lt;/strong&gt; é fundamental pro time evoluir sozinho. Na prática, isso significa trocar aprovação prévia por trilho:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decisões estruturais viram RFC/ADR — documento público, discussão assíncrona, decisão registrada.&lt;/li&gt;
&lt;li&gt;Qualidade vira automação — review, testes, lint, limite de tamanho de PR — e não uma pessoa de plantão pra dizer "pode".&lt;/li&gt;
&lt;li&gt;Domínio tem dono explícito, então a pessoa sabe onde ela tem autonomia total e onde ela precisa alinhar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A regra que eu tento seguir: &lt;strong&gt;controle na saída, não na entrada.&lt;/strong&gt; Você não pede permissão pra tentar, você garante que o que sai tem qualidade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que isso é ainda mais crítico em empresa crescendo
&lt;/h2&gt;

&lt;p&gt;Pra empresa em crescimento isso é vital, porque é exatamente através desses movimentos que &lt;strong&gt;surgem as novas lideranças&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Área nova sendo criada precisa de alguém pra guiar. E adivinha quem você escolhe? Não é quem reclamou mais alto. É quem já vinha operando como owner sem ninguém mandar.&lt;/p&gt;

&lt;p&gt;Na Monest a gente saiu de um time de tecnologia com 10 pessoas em janeiro de 2025 para mais de 50 em junho de 2026. Construir uma cultura data-driven, com controle de qualidade e sem burocracia, foi essencial pra gente conseguir crescer otimizando eficiência e não virar uma máquina de reuniões de aprovação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fechando
&lt;/h2&gt;

&lt;p&gt;Se você está no começo da carreira e enxerga mil coisas erradas onde trabalha: parabéns, você tem o olho. Falta a segunda metade.&lt;/p&gt;

&lt;p&gt;Escolhe &lt;strong&gt;uma&lt;/strong&gt;. A que mais dói. Monta o 1-3-1. Leva.&lt;/p&gt;

&lt;p&gt;E se você lidera: olha pro seu processo e pergunta honestamente quantas decisões reversíveis ainda estão passando por você. Cada uma delas é uma pessoa high-agency esperando na fila.&lt;/p&gt;

&lt;p&gt;Talk is cheap. Sempre foi.&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>career</category>
      <category>management</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Você não vai mais entregar código. Você vai entregar times que entregam código.</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 22 Feb 2026 21:26:39 +0000</pubDate>
      <link>https://dev.to/madmorett/voce-nao-vai-entregar-mais-codigo-19nl</link>
      <guid>https://dev.to/madmorett/voce-nao-vai-entregar-mais-codigo-19nl</guid>
      <description>&lt;p&gt;Quando você é dev, você controla a qualidade do que sai das suas mãos. Se algo vai pra produção com seu nome, você garante que tá do jeito que você quer.&lt;/p&gt;

&lt;p&gt;Quando você vira Head, isso muda. Você não entrega mais código. Você entrega times que entregam código.&lt;/p&gt;

&lt;p&gt;E isso dói.&lt;/p&gt;

&lt;h2&gt;
  
  
  O desespero de ver "diferente"
&lt;/h2&gt;

&lt;p&gt;No começo, eu olhava as entregas e ficava desesperado. Via um PR e pensava "eu teria feito diferente". Via uma arquitetura e pensava "não era assim que eu faria".&lt;/p&gt;

&lt;p&gt;A tentação era meter o dedo em tudo. Microgerenciar cada decisão, cada IF, cada nome de variável.&lt;/p&gt;

&lt;p&gt;Cheguei a fazer isso. Não escala. Você vira gargalo, o time para de pensar sozinho, e você não consegue fazer seu trabalho de verdade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deixar o time aprender
&lt;/h2&gt;

&lt;p&gt;Teve PR que eu vi débito técnico. Nada crítico, mas débito claro. Deixei. Queria ver se o time ia perceber sozinho.&lt;/p&gt;

&lt;p&gt;Percebeu. Corrigiu no sprint seguinte. Sem eu precisar falar nada.&lt;/p&gt;

&lt;p&gt;Claro que tem coisa e coisa. Se fosse algo crítico, eu teria intervindo. Mas parte de escalar é saber onde dá pra deixar o time aprender sozinho.&lt;/p&gt;

&lt;p&gt;Seu papel é criar o sistema. Não é operar o sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como a gente fez na Monest 💜
&lt;/h2&gt;

&lt;p&gt;Pra escalar qualidade sem microgerenciar, a gente criou camadas de proteção:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automação.&lt;/strong&gt; Lint, tipagem, padrões de código. Se dá pra automatizar, a máquina cobra.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI como guardiã.&lt;/strong&gt; Dezenas de guidelines alimentam um agente interno. A mesma AI revisa PRs e O approve dela é obrigatório. Se você programa com AI, ela já faz no padrão Monest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RFC antes, ADR depois.&lt;/strong&gt; Feature grande passa por RFC no GitHub, aprovada por Tech Lead. Depois da entrega, ADR documenta as decisões. A AI tem contexto do começo ao fim.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentação que respira.&lt;/strong&gt; Pilares de engenharia no Notion. E um documento que todo mundo conhece: "O que um dev na Monest faz bem?!". Soft-skills, hard-skills, expectativas claras. Dev, Tech Lead, Data Engineer, cada função tem o seu.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rituais e cultura.&lt;/strong&gt; Engineering All-Hands, Post-Mortems, Tech Talks internas. Nada disso funciona se o time não compra a ideia. A cultura é a última linha de defesa.&lt;/p&gt;

&lt;h2&gt;
  
  
  A surpresa
&lt;/h2&gt;

&lt;p&gt;Quando você constrói esse sistema e essa cultura, uma coisa inesperada acontece.&lt;/p&gt;

&lt;p&gt;Você para de ver entregas "diferentes". Você começa a ver entregas melhores do que você faria.&lt;/p&gt;

&lt;p&gt;Hoje tenho lideranças técnicas e engenheiros entregando muito melhor do que eu faria.&lt;/p&gt;

&lt;p&gt;Seu papel é garantir que a barra de qualidade seja alta. O time faz o resto. E te supera.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lição
&lt;/h2&gt;

&lt;p&gt;Meu papel não é mais entregar código. É construir o sistema que permite 40+ pessoas entregarem no nível que a Monest precisa.&lt;/p&gt;

&lt;p&gt;Se eu ainda quisesse controlar cada linha, a gente ainda seria 12.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Esse é o sexto post de uma série sobre lições que aprendi no meu primeiro ano como Head de Tecnologia. Semana que vem tem mais.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cto</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Contratando para áreas que você não domina</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 08 Feb 2026 14:36:16 +0000</pubDate>
      <link>https://dev.to/madmorett/contratando-para-areas-que-voce-nao-domina-1gh3</link>
      <guid>https://dev.to/madmorett/contratando-para-areas-que-voce-nao-domina-1gh3</guid>
      <description>&lt;p&gt;Tenho 10 anos de experiência em tecnologia. Nove deles foram como desenvolvedor ou tech lead. Sempre perto de código.&lt;/p&gt;

&lt;p&gt;Quando você vira Head de Tech, isso muda. De repente você precisa gerenciar e guiar áreas que nunca foram suas. E uma das primeiras que me pegou foi segurança da informação.&lt;/p&gt;

&lt;p&gt;A Monest 💜 é uma empresa de cobrança com AI. Processamos dados de milhares de devedores todo mês. Ser seguro aqui não é diferencial, é requisito.&lt;/p&gt;

&lt;p&gt;Quando entrei, a segurança era terceirizada. Funcionava, mas eu queria alguém interno. Alguém que vivesse o dia a dia da operação, que conhecesse nossos sistemas, que pudesse construir uma cultura de segurança de dentro pra fora.&lt;/p&gt;

&lt;p&gt;Eu precisava montar essa área. Contratar a primeira pessoa. Estruturar.&lt;/p&gt;

&lt;p&gt;O problema: eu mal sabia a diferença prática entre blue team e red team. Como eu ia julgar se um candidato era bom se eu não entendia o trabalho que ele ia fazer?&lt;/p&gt;

&lt;h2&gt;
  
  
  Pedindo ajuda
&lt;/h2&gt;

&lt;p&gt;Fui conversar com o &lt;a href="https://www.linkedin.com/in/aneto/" rel="noopener noreferrer"&gt;Alexandre Neto&lt;/a&gt;, CTO renomado e um dos investidores da Monest. Expliquei minha dor: precisava acertar nessa contratação, mas não tinha base técnica pra avaliar.&lt;/p&gt;

&lt;p&gt;Ele me deu um panorama do que buscar na posição. E fez algo ainda mais valioso: me conectou com o &lt;a href="https://www.linkedin.com/in/ricardo-barbosa-gomes/" rel="noopener noreferrer"&gt;Ricardo Barbosa&lt;/a&gt;, Coordenador de Segurança do Bradesco, com quem ele já tinha trabalhado.&lt;/p&gt;

&lt;p&gt;O Ricardo me ensinou o que esperar de um profissional de segurança. E participou da entrevista comigo.&lt;/p&gt;

&lt;p&gt;Um mês depois, contratamos o &lt;a href="https://www.linkedin.com/in/paulo-roberto-de-assis/" rel="noopener noreferrer"&gt;Paulo Roberto&lt;/a&gt;. Ele se candidatou pra vaga e foi o selecionado.&lt;/p&gt;

&lt;p&gt;Hoje, quase um ano depois, o Paulo estruturou a área de segurança internamente. Junto com a &lt;a href="https://www.linkedin.com/in/gabriela-lemes-8b54301a6/" rel="noopener noreferrer"&gt;Gabriela Lemes&lt;/a&gt;, responsável pela LGPD, passamos por 22 due diligences de segurança de clientes em 2025. Estamos caminhando cada vez mais perto da ISO 27001.&lt;/p&gt;

&lt;h2&gt;
  
  
  O modelo que funcionou
&lt;/h2&gt;

&lt;p&gt;Esse não foi um caso isolado. Usei o mesmo modelo pra estruturar a área de Dados. Busquei mentores externos que conheciam o que eu não conhecia.&lt;/p&gt;

&lt;p&gt;O padrão é simples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reconhecer que você não sabe.&lt;/strong&gt; Parece óbvio, mas o ego atrapalha. A tentação é fingir que dá conta sozinho.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Buscar quem sabe.&lt;/strong&gt; Não precisa ser um consultor pago. Pode ser um investidor, um contato de rede, alguém que você admira. A maioria das pessoas topa ajudar se você pedir direito.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trazer pra dentro do processo.&lt;/strong&gt; Não é só pedir conselho. É pedir pra participar da entrevista, validar o perfil, revisar o escopo da vaga.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lição
&lt;/h2&gt;

&lt;p&gt;Virar Head de Tech não significa que você precisa dominar tudo. Significa que você precisa garantir que as áreas estejam bem estruturadas, mesmo as que você não entende.&lt;/p&gt;

&lt;p&gt;E a melhor forma de fazer isso é se cercar de gente que sabe mais que você.&lt;/p&gt;

&lt;p&gt;Pedir ajuda não é fraqueza. É estratégia.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Esse é o quinto post de uma série sobre lições que aprendi no meu primeiro ano como Head de Tecnologia. Semana que vem tem mais.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cto</category>
      <category>startup</category>
      <category>security</category>
    </item>
    <item>
      <title>As melhores pessoas precisam saber que você existe</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 01 Feb 2026 22:39:47 +0000</pubDate>
      <link>https://dev.to/madmorett/as-melhores-pessoas-precisam-saber-que-voce-existe-1njd</link>
      <guid>https://dev.to/madmorett/as-melhores-pessoas-precisam-saber-que-voce-existe-1njd</guid>
      <description>&lt;p&gt;Muita gente acha que líder técnico não tem que ficar postando em rede social. Que isso é coisa de influencer, de quem quer vender curso.&lt;/p&gt;

&lt;p&gt;Eu pensava parecido. Até perceber uma coisa:&lt;/p&gt;

&lt;p&gt;Se a empresa tem a visão correta, a cultura correta, e você fornece meios pros seus desenvolvedores performarem, o que muda o jogo é a qualidade do seu time.&lt;/p&gt;

&lt;p&gt;Ferramentas, processos e metodologias importam. Mas quem faz tudo isso funcionar são as pessoas&lt;/p&gt;

&lt;p&gt;E o melhor jeito de ter as melhores pessoas é fazendo com que elas &lt;em&gt;queiram&lt;/em&gt; trabalhar com você.&lt;/p&gt;

&lt;p&gt;A pergunta é: como essas pessoas vão saber que você existe?&lt;/p&gt;

&lt;h2&gt;
  
  
  Como eu contratei um Tech Lead pelo Twitter
&lt;/h2&gt;

&lt;p&gt;Durante o ano de 2025, eu postei no meu &lt;a href="https://x.com/Morett_the_best" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; sobre desafios técnicos que a gente passava na Monest 💜. Coisas reais. Problemas de escala, decisões de arquitetura, erros que a gente cometeu.&lt;/p&gt;

&lt;p&gt;Nada polido. Nada pensado pra viralizar. Só o dia a dia de quem tá construindo produto.&lt;/p&gt;

&lt;p&gt;Um desses posts chegou no &lt;a href="https://x.com/samsantosb" rel="noopener noreferrer"&gt;Samuel&lt;/a&gt;. Ele tem 10k+ seguidores no Twitter, é referência técnica na bolha dele. Viu o que a gente tava fazendo e pensou: "esses caras devem estar fazendo uma coisa legal."&lt;/p&gt;

&lt;p&gt;Ele veio falar comigo.&lt;/p&gt;

&lt;p&gt;Hoje o Samuel é Tech Lead na Monest 💜, liderando nossa frente de canais (Voz e WhatsApp).&lt;/p&gt;

&lt;p&gt;Não teve recruiter. Não teve vaga publicada no LinkedIn. Conteúdo real atraiu talento real.&lt;/p&gt;

&lt;p&gt;E o Samuel não é o único. Tem outras pessoas que trabalham hoje na Monest 💜, ajudando a gente a revolucionar o mercado de cobrança todo dia, que vieram de relacionamentos feitos na internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que isso funciona
&lt;/h2&gt;

&lt;p&gt;Os melhores profissionais que eu conheço não ficam procurando vaga. Eles estão trabalhando, aprendendo, e observando.&lt;/p&gt;

&lt;p&gt;Observando quem tá resolvendo problemas interessantes. Quem pensa de um jeito que faz sentido pra eles. Quem trata o time de um jeito que eles gostariam de ser tratados.&lt;/p&gt;

&lt;p&gt;Quando você posta sobre como resolve problemas, como pensa sobre arquitetura, como lida com erro, você tá mostrando quem você é como líder. Sem filtro de processo seletivo, sem discurso de página de carreiras.&lt;/p&gt;

&lt;p&gt;E isso atrai gente que se identifica com o jeito que você trabalha. Gente que já chega alinhada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Não é sobre viralizar
&lt;/h2&gt;

&lt;p&gt;Não precisa ter milhões de seguidores. Não precisa fazer post todo dia. Não precisa virar influencer.&lt;/p&gt;

&lt;p&gt;É sobre ser visível na sua comunidade técnica.&lt;/p&gt;

&lt;p&gt;Postar aquele problema que você resolveu. Compartilhar uma decisão que deu certo ou errado. Contar o que você tá aprendendo.&lt;/p&gt;

&lt;p&gt;Isso já é suficiente pra que as pessoas certas te encontrem.&lt;/p&gt;

&lt;h2&gt;
  
  
  O livro que me fez levar isso a sério
&lt;/h2&gt;

&lt;p&gt;Li no "The Engineering Executive's Primer" do Will Larson que como líder, sua rede é seu ativo mais importante. Não só pra trocar ideias com outros líderes, mas pra construir o time que você precisa.&lt;/p&gt;

&lt;p&gt;Eu sempre soube disso intuitivamente. Mas ver escrito me fez parar de tratar rede social como opcional.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lição
&lt;/h2&gt;

&lt;p&gt;Você pode ter a melhor visão, a melhor cultura, o melhor produto. Mas quem constrói tudo isso são as pessoas.&lt;/p&gt;

&lt;p&gt;E as melhores pessoas precisam saber que você existe antes de querer trabalhar com você.&lt;/p&gt;

&lt;p&gt;Isso não é vaidade. Isso é estratégia.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Esse é o quarto post de uma série sobre lições que aprendi no meu primeiro ano como Head de Tecnologia. Semana que vem tem mais.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cto</category>
      <category>bolhadev</category>
    </item>
    <item>
      <title>O medo de ficar pra trás</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 25 Jan 2026 14:10:46 +0000</pubDate>
      <link>https://dev.to/madmorett/o-medo-de-ficar-pra-tras-59ne</link>
      <guid>https://dev.to/madmorett/o-medo-de-ficar-pra-tras-59ne</guid>
      <description>&lt;p&gt;Você também sente que está ficando pra trás porque todo mês surge uma tecnologia nova?&lt;/p&gt;

&lt;p&gt;Em janeiro de 2025, eu tinha acabado de assumir como &lt;strong&gt;Head de Tecnologia&lt;/strong&gt; da &lt;strong&gt;Monest&lt;/strong&gt; 💜. Tinha budget pra dobrar o time, um esboço de planejamento, e uma pergunta na cabeça: onde alocar essa galera nova?&lt;/p&gt;

&lt;p&gt;1 mês antes, a Anthropic havia lançado o &lt;strong&gt;MCP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Meu LinkedIn explodiu. "O futuro da integração de AI." Todo mundo falando. Todo mundo implementando. Todo mundo menos a gente.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Monest&lt;/strong&gt; é uma empresa de AI. E a gente &lt;strong&gt;não tinha MCP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Bateu a ansiedade. Será que eu deveria parar tudo e colocar o time pra explorar isso?&lt;/p&gt;

&lt;h2&gt;
  
  
  A pergunta que me acalmou
&lt;/h2&gt;

&lt;p&gt;Me forcei a pensar: o MCP invalida nossa estratégia, ou é algo que dá pra incorporar depois?&lt;/p&gt;

&lt;p&gt;Era a segunda opção.&lt;/p&gt;

&lt;p&gt;Seis meses depois, implementamos MCP. Mas não como produto principal. &lt;/p&gt;

&lt;p&gt;Nossos Biz Devs usam pra consultar insights da operação de cobrança. &lt;/p&gt;

&lt;p&gt;Inovamos onde fazia sentido, e o resto da energia foi pra escalar nossa AI de cobrança, onde crescemos 4x a quantidade de conversas por Voz e WhatsApp em 2025.&lt;/p&gt;

&lt;p&gt;Se eu tivesse parado tudo em janeiro, nada disso teria acontecido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nenhuma tecnologia se consolida do dia pra noite
&lt;/h2&gt;

&lt;p&gt;React foi lançado em 2013. Só em 2015 que Netflix e Airbnb adotaram. Virou mainstream em 2016. Três anos.&lt;/p&gt;

&lt;p&gt;Docker foi lançado em 2013. Em 2017, adoção em empresas era 20%. Só em 2021 passou de 90%. Oito anos.&lt;/p&gt;

&lt;p&gt;Tecnologia muda as coisas. Mas no ritmo dela, não no ritmo do hype.&lt;/p&gt;

&lt;h2&gt;
  
  
  Não é pra ignorar o novo
&lt;/h2&gt;

&lt;p&gt;Não tô dizendo pra fingir que tecnologia nova não existe. Tô dizendo pra dosar.&lt;/p&gt;

&lt;p&gt;O que funciona pra mim:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separar sinal de ruído.&lt;/strong&gt; Se pessoas que eu respeito estão falando de algo, presto atenção. Se só tem post patrocinado e tutorial raso, ignoro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estudar antes de implementar.&lt;/strong&gt; Fiz POCs de MCP internamente antes de decidir onde usar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Perguntar: isso resolve um problema real nosso agora?&lt;/strong&gt; MCP não resolvia nosso problema de janeiro. Ia criar trabalho novo sem entregar valor imediato.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lição
&lt;/h2&gt;

&lt;p&gt;A ansiedade de ficar pra trás é real. Mas a maioria das tecnologias leva anos pra se consolidar.&lt;/p&gt;

&lt;p&gt;Você tem tempo.&lt;/p&gt;

&lt;p&gt;Inovar não é adotar tudo primeiro. É saber onde colocar energia pra gerar resultado de verdade.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Esse é o terceiro post de uma série sobre lições que aprendi no meu primeiro ano como Head de Tecnologia. Semana que vem tem mais.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cto</category>
      <category>leadership</category>
      <category>techlead</category>
    </item>
    <item>
      <title>O delay entre esforço e recompensa</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 18 Jan 2026 15:20:07 +0000</pubDate>
      <link>https://dev.to/madmorett/o-delay-entre-esforco-e-recompensa-52dk</link>
      <guid>https://dev.to/madmorett/o-delay-entre-esforco-e-recompensa-52dk</guid>
      <description>&lt;p&gt;Na vida real, você não faz uma quest e já ganha a recompensa.&lt;/p&gt;

&lt;p&gt;Em jogos, você mata o monstro e o loot cai na hora. No TikTok, você scrolla e a dopamina vem em segundos. Mas quando você tenta mudar cultura ou processo numa empresa, o ciclo é outro: &lt;strong&gt;meses entre o esforço e o resultado&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O alerta que salvou o dia
&lt;/h2&gt;

&lt;p&gt;Em fevereiro, o time começou a implementar alertas customizados de monitoramento no New Relic. Não foi glamouroso. Foi trabalho chato de configurar thresholds, pensar em cenários de falha, escrever mensagens de alerta que fizessem sentido.&lt;/p&gt;

&lt;p&gt;Dois meses depois, em abril, um desses alertas disparou no final da manhã. Nossas recebimento de mensagens tinha ficado fora do ar.&lt;/p&gt;

&lt;p&gt;Detectamos na hora. Corrigimos em 15 minutos.&lt;/p&gt;

&lt;p&gt;Sem aquele alerta, só descobriríamos horas depois. Milhares de negociações perdidas. Clientes frustrados tentando fazer acordos e não conseguindo.&lt;/p&gt;

&lt;p&gt;O trabalho de fevereiro só mostrou valor em abril. E se nada tivesse quebrado, talvez o time nunca percebesse o quanto aquele esforço valeu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Os números que demoraram pra aparecer
&lt;/h2&gt;

&lt;p&gt;Entre janeiro e fevereiro, implementamos processos de post-mortem, melhoramos code review e introduzimos testes automatizados.&lt;/p&gt;

&lt;p&gt;Sabe quando vimos o impacto real? Em agosto.&lt;/p&gt;

&lt;p&gt;Tickets de bugs caíram de 20% para 10% do esforço de desenvolvimento. Metade.&lt;/p&gt;

&lt;p&gt;Seis meses entre plantar e colher.&lt;/p&gt;

&lt;h2&gt;
  
  
  O dev que foi entendendo aos poucos
&lt;/h2&gt;

&lt;p&gt;No começo do ano, comecei a insistir com o time sobre a importância de logs bem feitos. Como usar o New Relic direito. Como pensar em observabilidade desde o início.&lt;/p&gt;

&lt;p&gt;Tinha um dev que ouvia, fazia o básico, mas não tinha clicado ainda.&lt;/p&gt;

&lt;p&gt;Com o tempo, ele foi percebendo que a vida ficava mais fácil quando os logs estavam lá. Que debugar produção virava minutos em vez de horas. Que ele dormia mais tranquilo.&lt;/p&gt;

&lt;p&gt;Não teve um momento de virada. Foi aos poucos. Meses até virar natural.&lt;/p&gt;

&lt;p&gt;Isso é o oposto de dopamina rápida. É investimento de longo prazo em alguém.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que isso é difícil
&lt;/h2&gt;

&lt;p&gt;Esse delay causa ansiedade em todo mundo.&lt;/p&gt;

&lt;p&gt;O CEO pergunta "cadê o resultado daquele processo novo?". O time questiona "pra que perder tempo com isso?". E você mesmo fica se perguntando se tá no caminho certo.&lt;/p&gt;

&lt;p&gt;A tentação é abandonar o processo antes de validar. Ou mudar tudo porque não viu resultado em duas semanas.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que funcionou pra mim
&lt;/h2&gt;

&lt;p&gt;Três coisas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clareza de propósito.&lt;/strong&gt; Se você não sabe por que tá fazendo algo, não vai aguentar esperar o resultado. Antes de implementar qualquer mudança, eu preciso conseguir explicar em uma frase por que aquilo importa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Medir os pequenos ganhos.&lt;/strong&gt; O resultado final demora, mas sinais aparecem no caminho. Um deploy que não quebrou. Um bug que foi pego antes de ir pra produção. Um dev que fez a pergunta certa. Esses sinais mantêm o time engajado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paciência.&lt;/strong&gt; Não tem atalho. Às vezes você só precisa esperar.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lição
&lt;/h2&gt;

&lt;p&gt;Mudança de cultura não funciona no ritmo de TikTok. Funciona no ritmo de plantação: você planta, cuida, espera, e torce pra chover na hora certa.&lt;/p&gt;

&lt;p&gt;Os frutos chegam. Mas não no tempo que a ansiedade quer.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Esse é o segundo post de uma série sobre lições que aprendi no meu primeiro ano como Head de Tecnologia. Semana que vem tem mais.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>monitoring</category>
      <category>motivation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Como tirar o mindset de early-stage sem criar burocracia</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 11 Jan 2026 05:04:06 +0000</pubDate>
      <link>https://dev.to/madmorett/como-tirar-o-mindset-de-early-stage-sem-criar-burocracia-3glj</link>
      <guid>https://dev.to/madmorett/como-tirar-o-mindset-de-early-stage-sem-criar-burocracia-3glj</guid>
      <description>&lt;h1&gt;
  
  
  Como tirar o mindset de early-stage sem criar burocracia
&lt;/h1&gt;

&lt;p&gt;Quando entrei na Monest como Head de Tecnologia, o time de tech tinha 12 pessoas. Um ano depois, somos 35.&lt;/p&gt;

&lt;p&gt;Esse crescimento muda tudo. Processos que funcionavam com 12 pessoas simplesmente quebram com 35. O problema é que ninguém percebe na hora. O time continua operando do mesmo jeito, até que algo estoura.&lt;/p&gt;

&lt;p&gt;E quando você tenta mudar, ouve a frase que todo líder de tech conhece: "mas sempre foi assim".&lt;/p&gt;

&lt;h2&gt;
  
  
  O desafio real
&lt;/h2&gt;

&lt;p&gt;O difícil não é identificar o que precisa mudar. O difícil é mudar sem transformar a empresa numa máquina burocrática que demora 3 semanas pra fazer um deploy.&lt;/p&gt;

&lt;p&gt;Startup vive de velocidade. Se você cria processo demais, mata o que fez a empresa chegar até ali.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que mudamos
&lt;/h2&gt;

&lt;p&gt;Vou dar quatro exemplos concretos de coisas que implementamos e que geraram atrito inicial:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testes e2e obrigatórios.&lt;/strong&gt; Antes não tinha. O time testava na mão, ou não testava. Com 12 pessoas, todo mundo conhecia o sistema inteiro e sabia o que podia quebrar. Com 35, ninguém tem essa visão completa. Testes e2e viraram obrigatórios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tipagem real no TypeScript.&lt;/strong&gt; Nosso "TypeScript" era JavaScript com extensão &lt;code&gt;.ts&lt;/code&gt;. Qualquer coisa era &lt;code&gt;any&lt;/code&gt;. Isso funcionava quando todo mundo sabia o que cada função esperava. Não funciona mais. Escrevi sobre como eliminamos 4.041 erros de TypeScript em 6 meses &lt;a href="https://dev.to/monest/como-eliminamos-4041-erros-de-typescript-em-6-meses-320a"&gt;nesse artigo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observabilidade como regra.&lt;/strong&gt; Implementamos New Relic em tudo. Antes, quando algo dava problema em produção, era um detetive tentando reproduzir o erro localmente. Agora a gente sabe exatamente o que aconteceu, onde, e por quê. Com 12 pessoas, dava pra perguntar "quem mexeu nisso?". Com 35, você precisa de dados, não de memória.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RFC pra features novas.&lt;/strong&gt; Antes, alguém tinha uma ideia e começava a codar. Agora, se é algo que muda o rumo do produto, precisa de um documento mínimo explicando o que, por que, e como. Não precisa ser longo. Mas precisa existir.&lt;/p&gt;

&lt;p&gt;Nos quatro casos, a reação inicial foi a mesma: "mas antes não precisava".&lt;/p&gt;

&lt;h2&gt;
  
  
  Como convencer sem impor
&lt;/h2&gt;

&lt;p&gt;A resposta pra "antes não precisava" não pode ser "agora precisa porque eu mandei". Isso não funciona e cria ressentimento.&lt;/p&gt;

&lt;p&gt;O que funcionou pra mim foi mostrar dados. Não opinião, não "melhores práticas", não "em empresa séria é assim". Dados.&lt;/p&gt;

&lt;p&gt;Depois de um ano com essas mudanças, nossos números mostram:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50% menos tickets de suporte&lt;/li&gt;
&lt;li&gt;36% menos post-mortems no Q4 comparado ao Q1, mesmo com o time quase 3x maior e fazendo 80+ deploys por semana&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quando você mostra que a "chatice" gerou resultado concreto, a conversa muda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde não exagerar
&lt;/h2&gt;

&lt;p&gt;Tão importante quanto saber o que implementar é saber onde parar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exigimos testes e2e, mas não exigimos 100% de coverage. &lt;/li&gt;
&lt;li&gt;RFC pra feature nova, mas não pra bugfix. &lt;/li&gt;
&lt;li&gt;Tipagem correta, mas com migração gradual.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A pergunta que me faço antes de criar qualquer processo novo: "isso vai ajudar o time a entregar melhor, ou só vai dar mais trabalho?"&lt;/p&gt;

&lt;p&gt;Se a resposta for só mais trabalho, não implemento.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lição
&lt;/h2&gt;

&lt;p&gt;Crescer dói. O jeito que funcionava antes vai parar de funcionar, e você vai precisar convencer pessoas a mudar algo que elas não veem como problema.&lt;/p&gt;

&lt;p&gt;O equilíbrio é: criar processos que protegem a empresa sem criar burocracia que trava a empresa.&lt;/p&gt;

&lt;p&gt;Não existe fórmula. É tentativa, erro, e prestar atenção nos resultados.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cto</category>
      <category>techlead</category>
      <category>leadership</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Fri, 05 Dec 2025 21:31:39 +0000</pubDate>
      <link>https://dev.to/madmorett/-1c3</link>
      <guid>https://dev.to/madmorett/-1c3</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" class="crayons-story__hidden-navigation-link"&gt;How I made BeeThreads and what doest it solve&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/samsantosb" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1073001%2F375cd36f-421a-477c-a8c2-eef450c302d2.jpg" alt="samsantosb profile" class="crayons-avatar__image" width="400" height="400"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/samsantosb" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Sam
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Sam
                
                
              
              &lt;div id="story-author-preview-content-3087184" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/samsantosb" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1073001%2F375cd36f-421a-477c-a8c2-eef450c302d2.jpg" class="crayons-avatar__image" alt="" width="400" height="400"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Sam&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 5 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" id="article-link-3087184"&gt;
          How I made BeeThreads and what doest it solve
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/node"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;node&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;6&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>showdev</category>
      <category>node</category>
      <category>performance</category>
    </item>
    <item>
      <title>Como Eliminamos 4.041 Erros de TypeScript em 6 Meses</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Mon, 10 Nov 2025 20:38:44 +0000</pubDate>
      <link>https://dev.to/monest/como-eliminamos-4041-erros-de-typescript-em-6-meses-320a</link>
      <guid>https://dev.to/monest/como-eliminamos-4041-erros-de-typescript-em-6-meses-320a</guid>
      <description>&lt;p&gt;Quando assumi como Head de Tecnologia da Monest em janeiro de 2025, me deparei com um cenário que muitos times de engenharia conhecem bem: TypeScript configurado com &lt;code&gt;strict: false&lt;/code&gt;. Na prática, isso significava que nosso "TypeScript" era apenas JavaScript com extensão &lt;code&gt;.ts&lt;/code&gt; — sem as verdadeiras garantias de tipo que tornam o TypeScript valioso.&lt;/p&gt;

&lt;p&gt;O problema era simples de identificar: código como &lt;code&gt;object.value&lt;/code&gt; onde &lt;code&gt;object&lt;/code&gt; poderia ser &lt;code&gt;undefined&lt;/code&gt; passava tranquilamente no build, só para explodir em runtime. Mas a solução? Essa era outra história.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Desafio: 4.041 Erros de Uma Vez
&lt;/h2&gt;

&lt;p&gt;Quando finalmente ativamos &lt;code&gt;strict: true&lt;/code&gt; para avaliar a situação, fomos recebidos por uma parede vermelha no VSCode: &lt;strong&gt;4.041 erros de TypeScript&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ninguém consegue resolver 4.041 erros do dia para a noite. E mesmo que conseguisse, o risco de quebrar funcionalidades críticas em produção — especialmente em uma startup de cobrança por IA como a Monest — era inaceitável.&lt;/p&gt;

&lt;p&gt;Precisávamos de uma estratégia diferente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nossa Abordagem: Migração Gradual e Sustentável
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Strict em Dev, Permissivo em Prod
&lt;/h3&gt;

&lt;p&gt;A primeira decisão foi aparentemente contraditória, mas fundamental:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;code&gt;strict: true&lt;/code&gt; em desenvolvimento — para que os erros aparecessem na nossa cara enquanto editávamos arquivos&lt;/li&gt;
&lt;li&gt;⚠️ &lt;code&gt;strict: false&lt;/code&gt; em deploy — para que a build funcionasse mesmo com erros pendentes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isso nos deu visibilidade do problema sem bloquear o time ou comprometer entregas.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Uma GitHub Action para Criar Accountability
&lt;/h3&gt;

&lt;p&gt;Criamos uma GitHub Action que contava os erros de TypeScript a cada PR. A regra era simples: &lt;strong&gt;cada PR precisava reduzir pelo menos 1 erro&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%2Fd4vkvbkq6vwkz7izfkx2.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%2Fd4vkvbkq6vwkz7izfkx2.png" alt="Comentário no GitHub dizendo que foram removidos erros o suficiente" width="799" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Não importava se você estava trabalhando em uma nova feature ou em um bugfix — você tinha que resolver ao menos um débito técnico de TypeScript. Sem exceções.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A Regra de Ouro: Produção em Primeiro Lugar
&lt;/h3&gt;

&lt;p&gt;Estabelecemos uma regra de ouro para guiar decisões difíceis:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"O sistema funciona em produção. Na dúvida entre alterar o código ou o tipo, altere o tipo."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essa diretriz foi crucial. Em vez de tentar "corrigir" código que funcionava (e potencialmente introduzir bugs), priorizamos ajustar as definições de tipo para refletir a realidade do código existente. Refatorações podiam vir depois, quando entendêssemos melhor cada parte do sistema.&lt;/p&gt;

&lt;p&gt;Nem tudo foi perfeito nessa jornada. Tivemos um deploy que acabou quebrando produção — ironicamente, o erro foi justamente fazer o oposto da nossa regra de ouro: confiamos no tipo (que estava errado) em vez do código (que funcionava). Foi um lembrete valioso de que tipos são ferramentas para nos ajudar a entender o código, não verdades absolutas sobre ele.&lt;/p&gt;

&lt;p&gt;Esse incidente reforçou ainda mais a importância da nossa abordagem cautelosa e incremental.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Visibilidade e Celebração do Progresso
&lt;/h3&gt;

&lt;p&gt;Incorporamos na nossa reunião de engineering all-hands o ritual de ver quantos erros tínhamos eliminado no mês. Transformamos o que poderia ser uma tarefa chata em um indicador de progresso coletivo.&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%2Fyb20yyy3plroi79hgzcg.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%2Fyb20yyy3plroi79hgzcg.png" alt="Gráfico em linha da diminuição de erros de TypeScript" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ver aquele número caindo mês a mês criou um senso de conquista compartilhada.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Atenção Especial para Código Crítico
&lt;/h3&gt;

&lt;p&gt;Para arquivos sensíveis — como nossa lógica de geração de acordos, o coração da nossa plataforma — criamos tickets específicos. Essas partes do código mereciam atenção focada e revisão cuidadosa, não podiam ser tratadas como "apenas mais um erro para resolver".&lt;/p&gt;

&lt;h2&gt;
  
  
  Os Resultados
&lt;/h2&gt;

&lt;p&gt;Mantivemos uma média de &lt;strong&gt;800 erros removidos por mês&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em &lt;strong&gt;6 meses&lt;/strong&gt;, chegamos a &lt;strong&gt;zero erros de TypeScript&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Hoje, em novembro de 2025, arquivos vermelhos com erros de TypeScript são coisa do passado na Monest. Mais importante: ganhamos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Confiança&lt;/strong&gt; — refatorações são menos arriscadas&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Produtividade&lt;/strong&gt; — o autocomplete realmente funciona&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Qualidade&lt;/strong&gt; — pegamos erros em tempo de desenvolvimento, não em produção&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Onboarding&lt;/strong&gt; — novos engenheiros entendem o código mais rapidamente&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lições Aprendidas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Débito técnico não se resolve em um sprint heroico
&lt;/h3&gt;

&lt;p&gt;Tentativas de "resolver tudo de uma vez" geralmente falham. Progresso consistente e incremental vence.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Automação cria disciplina
&lt;/h3&gt;

&lt;p&gt;A GitHub Action transformou a resolução de débito técnico de "quando der tempo" para "sempre, um pouco por vez".&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Visibilidade gera engajamento
&lt;/h3&gt;

&lt;p&gt;Compartilhar o progresso publicamente nas all-hands criou senso de propriedade coletiva.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Produção não pode esperar perfeição
&lt;/h3&gt;

&lt;p&gt;A configuração híbrida (strict em dev, permissivo em prod) nos deu o melhor dos dois mundos: visibilidade sem bloqueio.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Tipos servem o código, não o contrário
&lt;/h3&gt;

&lt;p&gt;Nosso único incidente em produção nos ensinou: quando os tipos contradizem código que funciona, questione os tipos primeiro.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>backend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Why You Shouldn't Use `as` in TypeScript 🚫</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Sun, 03 Nov 2024 14:36:39 +0000</pubDate>
      <link>https://dev.to/madmorett/why-you-shouldnt-use-as-in-typescript-3e5i</link>
      <guid>https://dev.to/madmorett/why-you-shouldnt-use-as-in-typescript-3e5i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;TypeScript, since its inception, has aimed to provide static typing for JavaScript, helping developers write safer and more reliable code. The &lt;code&gt;as&lt;/code&gt; operator was introduced to allow &lt;strong&gt;type assertions&lt;/strong&gt;, a powerful feature but one with great potential for misuse. In this article, we'll explore the creation and purpose of &lt;code&gt;as&lt;/code&gt;, common mistakes associated with its use, and how alternatives like &lt;code&gt;zod&lt;/code&gt; can offer a more robust solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Creation of &lt;code&gt;as&lt;/code&gt; in TypeScript
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;as&lt;/code&gt; keyword in TypeScript is used to inform the compiler that a value should be treated as a specific type, regardless of its original inference. It's useful in situations where the developer is certain about the correct type of a variable, but the compiler cannot infer it.&lt;/p&gt;

&lt;p&gt;For example:&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getValueFromSomewhere&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;valueAsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// I know `value` is a string!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;as&lt;/code&gt; tells the compiler that &lt;code&gt;value&lt;/code&gt; is a string, even though it was initially inferred as &lt;code&gt;unknown&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistake: Using &lt;code&gt;as&lt;/code&gt; with Fetch and JSON.parse
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;as&lt;/code&gt; is useful, it can easily be misused, especially in scenarios where data comes from external sources, such as APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  With Fetch
&lt;/h3&gt;

&lt;p&gt;When using &lt;code&gt;fetch&lt;/code&gt; to get data from an API, it's tempting to use &lt;code&gt;as&lt;/code&gt; to tell TypeScript what type of data to expect:&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="dl"&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;MyDataType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Beware!&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're telling TypeScript: "Trust me, &lt;code&gt;data&lt;/code&gt; is of type &lt;code&gt;MyDataType&lt;/code&gt;." The problem is that &lt;code&gt;fetch&lt;/code&gt; doesn't guarantee the format of the returned data. This can lead to runtime errors that TypeScript cannot predict or prevent.&lt;/p&gt;

&lt;h3&gt;
  
  
  With JSON.parse
&lt;/h3&gt;

&lt;p&gt;The same issue arises when using &lt;code&gt;JSON.parse()&lt;/code&gt;:&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;jsonString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"name": "John", "age": 30}&lt;/span&gt;&lt;span class="dl"&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;parsedData&lt;/span&gt; &lt;span class="o"&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;jsonString&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;MyDataType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Risky!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although &lt;code&gt;jsonString&lt;/code&gt; seems to contain an object of type &lt;code&gt;MyDataType&lt;/code&gt;, there are no guarantees. If the JSON structure changes or is incorrect, the code will fail silently, leading to hard-to-track bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Using &lt;code&gt;zod&lt;/code&gt; for Safe Type Validation
&lt;/h2&gt;

&lt;p&gt;To avoid these issues, it's better to validate external data before trusting it. &lt;code&gt;zod&lt;/code&gt; is a TypeScript schema validation library that can be used for this purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example with &lt;code&gt;fetch&lt;/code&gt; and &lt;code&gt;zod&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;z&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;zod&lt;/span&gt;&lt;span class="dl"&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;MyDataType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="dl"&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MyDataType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Now we are sure that `result.data` is of the correct type!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example with &lt;code&gt;JSON.parse&lt;/code&gt; and &lt;code&gt;zod&lt;/code&gt;
&lt;/h3&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;jsonString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"name": "John", "age": 30}&lt;/span&gt;&lt;span class="dl"&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;json&lt;/span&gt; &lt;span class="o"&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;jsonString&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MyDataType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Valid data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When It’s Safe to Use &lt;code&gt;as&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Although we’ve discussed the dangers of misusing &lt;code&gt;as&lt;/code&gt;, there is one specific scenario where I personally find it acceptable to use: &lt;strong&gt;Gradual Migration to TypeScript&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gradual Migration to TypeScript
&lt;/h3&gt;

&lt;p&gt;During the migration of a large JavaScript codebase to TypeScript, it might be necessary to use &lt;code&gt;as&lt;/code&gt; temporarily to maintain compatibility while you gradually add more specific and safe types to your code.&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;function&lt;/span&gt; &lt;span class="nf"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&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;typedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;MyDataType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Temporary use&lt;/span&gt;
    &lt;span class="c1"&gt;// Processing logic here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an acceptable use of &lt;code&gt;as&lt;/code&gt; during the transition but should be replaced by more precise types or validations as soon as possible.&lt;/p&gt;

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

&lt;p&gt;While &lt;code&gt;as&lt;/code&gt; can be a handy tool, its misuse, especially when dealing with dynamic or external data, can lead to silent and hard-to-debug runtime errors. Instead, adopting validation tools like &lt;code&gt;zod&lt;/code&gt; provides a more robust and secure approach, ensuring that data matches the expected types before trusting it in your TypeScript code. Personally, I would only use &lt;code&gt;as&lt;/code&gt; in the context of gradual migration to TypeScript, where its temporary nature is understood, and plans are in place to phase it out.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🔍 "Overlooked Use Cases in Your Tasks?"</title>
      <dc:creator>Matheus Morett</dc:creator>
      <pubDate>Mon, 04 Sep 2023 22:32:32 +0000</pubDate>
      <link>https://dev.to/madmorett/overlooked-use-cases-in-your-tasks-5cdg</link>
      <guid>https://dev.to/madmorett/overlooked-use-cases-in-your-tasks-5cdg</guid>
      <description>&lt;p&gt;Throughout my 8️⃣ years in software development, I've faced a recurring challenge: &lt;strong&gt;poorly specified tasks&lt;/strong&gt;. 😰&lt;/p&gt;

&lt;p&gt;How many times were use cases overlooked by the PO? And what if, during development, I forgot a crucial detail? 🤔 These oversights often only emerged during testing or, even worse, once users began interacting with the application. 😓&lt;/p&gt;

&lt;p&gt;This scenario began to shift for the better when I was fortunate enough to work with a PO who employed &lt;strong&gt;Gherkin&lt;/strong&gt; for specifications. 🌟 From that point on, &lt;strong&gt;the responsibility to define use cases was shared between the PO and myself&lt;/strong&gt;. This change not only made it easier to introduce automated testing but also helped me deliver more &lt;strong&gt;bug-free software&lt;/strong&gt;. 🛠️💡&lt;/p&gt;

&lt;p&gt;Let's dive into a practical example. 🧐&lt;/p&gt;

&lt;p&gt;Imagine you were given this User Story:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;As a user, I should be able to redeem a discount coupon at checkout. 🛍️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Translating this &lt;strong&gt;User Story&lt;/strong&gt; to automated tests in Jest:&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="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coupon Redemption based on User Story&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should allow users to redeem a discount coupon&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Mock checkout process&lt;/span&gt;
    &lt;span class="c1"&gt;// Insert coupon code&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalPrice&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDiscounted&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;However, this test seems quite general and lacks detail.&lt;/p&gt;

&lt;p&gt;Now, let's see how &lt;strong&gt;Gherkin&lt;/strong&gt; can refine this: 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scenario: Redeeming a valid coupon
Given the user is finalizing a purchase
When they enter a valid coupon code
Then the appropriate discount should be applied to the total 🟢

Scenario Redeeming an expired coupon
Given the user is finalizing a purchase
When they enter an expired coupon code
Then no discount should be applied
And a message stating the coupon has expired should be displayed. 🔴
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Translating the refined &lt;strong&gt;Gherkin&lt;/strong&gt; scenarios to &lt;strong&gt;Jest&lt;/strong&gt; tests:&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="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coupon Redemption based on Gherkin&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should apply discount for valid coupon&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Mock checkout process&lt;/span&gt;
    &lt;span class="c1"&gt;// Input valid coupon code&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalPrice&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDiscounted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should show error for expired coupon&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Mock checkout process&lt;/span&gt;
    &lt;span class="c1"&gt;// Input expired coupon code&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalPrice&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBeDiscounted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;displayErrorMessage&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coupon expired&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;Gherkin&lt;/strong&gt; specifications not only address the scenario of a valid coupon but also consider the situation of an expired coupon, which could easily be overlooked with a vaguer User Story.&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>testing</category>
      <category>agile</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
