<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pt-BR">
  <title>Blog Erik Figueiredo</title>
  <subtitle>Reflexões, tecnologia e opiniões por Erik Figueiredo.</subtitle>
  <link href="https://blog.erikfigueiredo.com.br/feed.xml" rel="self" />
  <link href="https://blog.erikfigueiredo.com.br/" />
  <updated>2026-07-14T00:00:00Z</updated>
  <id>https://blog.erikfigueiredo.com.br/</id>
  <author>
    <name>Erik Figueiredo</name>
  </author>
  <entry>
    <title>Raspberry Pi, mini-PC ou desktop: hardware pro homelab</title>
    <link href="https://blog.erikfigueiredo.com.br/posts/raspberry-pi-mini-pc-ou-desktop-hardware-homelab/" />
    <updated>2026-07-14T00:00:00Z</updated>
    <id>https://blog.erikfigueiredo.com.br/posts/raspberry-pi-mini-pc-ou-desktop-hardware-homelab/</id>
    <content type="html">&lt;div class=&quot;cover-image&quot;&gt;
  &lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blog.erikfigueiredo.com.br/img/B6ipvNs-fP-1200.webp 1200w&quot;&gt;&lt;img src=&quot;https://blog.erikfigueiredo.com.br/img/B6ipvNs-fP-1200.jpeg&quot; alt=&quot;Capa do artigo: Raspberry Pi, mini-PC ou desktop, hardware pro homelab&quot; width=&quot;1200&quot; height=&quot;800&quot; loading=&quot;lazy&quot;&gt;&lt;/picture&gt;
&lt;/div&gt;
&lt;p&gt;Eu sou dev a MUITO tempo e durante os anos aproveitei momentos bem legais da tecnologia, mas perdi MUITOS outros e hoje vou falar de um que QUASE perdi, mas foi por muito pouco.&lt;/p&gt;
&lt;p&gt;Em 2012 lançaram o Raspberry PI, não era um microcontrolador, não era um PC, era algo que somente ele era, um PC em uma placa que cabia na palma da mão, claro, fiquei doido querendo um, mas um designer gráfico casado, ganhando pouco e com o primeiro bebê a caminho... não dava nem pra sonhar com tão pouco.&lt;/p&gt;
&lt;p&gt;Os anos passaram e a vida virou, programação deu certo, e ca estamos, 14 anos depois e eu finalmente lembrei do RPI tão sonhado e que ficou lá atras, comprei o primeiro, paguei barato, 8GB de memória da quinta geração, gostei MUITO e aproveitei pra comprar o segundo Raspberry PI 5 8GB pra brincar de montar um cluster com K3S, infra na prática e do zero, sem ninguém provisionando nada, só eu mesmo, deveria bastar... e bastou.&lt;/p&gt;
&lt;p&gt;O revés da vida? Os preços dobraram, e eu que paguei barato digo que hoje, menos de um ano depois, ta o triplo do que eu paguei... culpa da IA.&lt;/p&gt;
&lt;p&gt;E pergunto, vale a pena montar um cluster com Raspberry PI hoje?&lt;/p&gt;
&lt;p&gt;Não tenho NENHUMA intenção de compartilhar valores de hardware atual, porque eu não sei quando você vai estar lendo isso, eu vou te dar o caminho pra comparar o que vale a pena pro seu caso com propriedade e conhecimento técnico, você vai criar sua receita, não eu.&lt;/p&gt;
&lt;h2&gt;Por que hardware é a decisão menos divertida (e mais importante)&lt;/h2&gt;
&lt;p&gt;Decidir seu hardware não é tão simples quanto decidir entre Swarm e K3S, com um pouco de paciência e Claude, da pra reverter todo o seu esquema, agora, se você comprar o hardware errado vai ter que conviver com as limitações dele, o hardware vai definir até onde você pode ir com o software.&lt;/p&gt;
&lt;p&gt;Um exemplo claro, quando eu montei meu PC atual a uns anos coloquei 64GB de memória, escolhi um I9 e uma placa de vídeo boa pra epoca (RTX 4070), decidi extrapolar um pouco onde podia, o que deu pra comprar de cara eu comprei, o que não deu comprei depois, mas hoje, anos depois, ainda colho os frutos dessa escolha, posso rodar LLMs 30B MoE com a memoria extra e a placa de vídeo enquanto trabalho confortávelmente, ouço música e dezenas de containers Docker que eu esqueci de fechar... porque quando decidi pelo hardware eu escolhi que queria escala, dois pentes de 16GB e depois mais 2 quando deu, a placa de vídeo veio depois e por ai foi.&lt;/p&gt;
&lt;p&gt;Infelizmente, gastar dinheiro em hardware pode não ser a coisa mais importante pra você, mas independente do seu poder aquisitivo, você precisa de escala e homogeneidade, você quer que os nós do seu cluster tenham o mesmo poder de processamento, pra garantir uma divisão simples e de fácil manutenção dos serviços.&lt;/p&gt;
&lt;p&gt;Tem gente montando cluster com celular usado! Você consegue, mas se tiver difícil, ainda vou falar em outro artigo como conseguir uma VPS poderosa e grátis!&lt;/p&gt;
&lt;!-- Gancho para um artigo sobre Ampere A1 da Oracle --&gt;
&lt;h2&gt;Os 3 candidatos em 2026&lt;/h2&gt;
&lt;p&gt;As possibilidades de candidatos para 2026 são enormes pra você que quer montar seu homelab, SBCs, SFF (mini PCs), Desktops, Servidor de Rack, Notebook ou SoMs e ainda tem os fora da curva, como celulares, roteadores (???) e até consoles de game e TVBox podem virar servidores, mas aqui eu vou cobrir 3 categorias que mais se encaixam no contexto geral:&lt;/p&gt;
&lt;p&gt;SBCs (Raspiberry PI), SFF (Intel N100/N97) e Desktops (Notebooks parcialmente cobertos também).&lt;/p&gt;
&lt;h3&gt;Raspberry Pi 5 8GB, o SBC mais famozinho&lt;/h3&gt;
&lt;p&gt;Na categoria de Single Board Computer (SBC), com certeza o RPI (Raspberry PI) é o mais famoso, mas ta longe de ser a única opção, Orange PI, Radxa Rock, Banana PI, Radxa X4, NVIDIA Jetson Orin Nano Super.... vale pesquisar MUITO, tem pra todos os gostos e poder aquesitivo, tem até o Raspberry Pi Zero 2 W (sério, eu achava que era microcontrolador, mas nunca tive um... ja vi por duzentão no ML).&lt;/p&gt;
&lt;p&gt;Minha escolha foi logo no clássico, minha filosofia, quanto mais famoso, mas documentação e suporte na internet.&lt;/p&gt;
&lt;p&gt;Comprei o primeiro, subi Ubuntu Server e joguei um Swarm com Gitea e umas parafernalhas pra funcionar, vamos falar disso em outro artigo, por hora, essa foi a minha escolha, e com certeza não escolheria ele hoje e você vai entender o porque no próximo tópico (sobre Mini-PCs).&lt;/p&gt;
&lt;!-- &quot;vamos falar disso em outro artigo&quot; - gancho para artigo prático de instalação do servidor --&gt;
&lt;p&gt;O salto do Raspberry Pi 4 para o Pi 5 (8GB) é o maior entre gerações da linha até hoje. O Pi 4 traz o Broadcom BCM2711 (quatro núcleos Cortex-A72 em 28nm a 1,5GHz, 1,8GHz em modelos mais recentes), enquanto o Pi 5 usa o BCM2712, quatro núcleos Cortex-A76 em 16nm a 2,4GHz. Na prática, a própria Raspberry mede algo em torno de 2 a 3× mais desempenho de CPU e GPU no Pi 5, com o Cortex-A76 entregando cerca de 35% mais IPC por clock, além de cerca de 30% mais banda de memória (LPDDR4X-4267 contra LPDDR4-3200). A mudança mais estrutural, porém, é o chip de I/O dedicado RP1, que tira os controladores de USB e Ethernet do gargalo antigo, e a porta PCIe 2.0 x1, que finalmente permite NVMe via HAT, transformando o Pi 5 num candidato sério a servidor. O custo dessa potência: o Pi 5 consome cerca de 70% mais energia e esquenta bem mais, exigindo refrigeração ativa para não sofrer throttling sob carga sustentada... sem cooler, ele passa dos 80°C e cai de volta a velocidades de Pi 4 em poucos minutos. O Pi 5 brilha mesmo é em tarefas paralelas, I/O pesado, mídia e emulação.&lt;/p&gt;
&lt;p&gt;No &lt;a href=&quot;https://gigglescore.com/&quot;&gt;GiggleScore&lt;/a&gt; você pode comparar vários modelos de SBC, a seguir o que cada métrica significa, mas cuidado, no que se refere a custo, pode mudar um pouco para o mercado brasileiro, então pesquisa ai.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Colunas do GiggleScore.com&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Board&lt;/strong&gt;, o modelo do SBC testado.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Price (USD)&lt;/strong&gt;, preço de referência em dólares.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Size of Pool&lt;/strong&gt;, quantas unidades daquele board contribuíram com resultados. Só indica confiança estatística (127 Pi 4 dão média mais sólida que 1 Orange Pi Zero sozinho).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LZMA&lt;/strong&gt;, desempenho bruto de CPU: MIPS médio no benchmark de compressão LZMA do 7-Zip. &lt;strong&gt;Maior = mais rápido.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gv2&lt;/strong&gt;, o Giggle Score: performance ponderada pelo preço em USD (custo-benefício). &lt;strong&gt;Menor = melhor valor&lt;/strong&gt; (menos dólar por performance).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LZMA Rank&lt;/strong&gt;, posição no ranking só de velocidade bruta (1º = mais rápido).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;G Rank&lt;/strong&gt;, posição no ranking de custo-benefício (1º = melhor valor).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;BOB Rank&lt;/strong&gt;, &amp;quot;Best Of Both&amp;quot;: ranking que equilibra performance E valor. 1º = melhor combinação dos dois mundos.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Observações&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Os três rankings dão vencedores diferentes: &lt;strong&gt;LZMA&lt;/strong&gt; → Raspberry Pi 5 8GB (mais rápido), &lt;strong&gt;Gv2&lt;/strong&gt; → Raspberry Pi 1 (melhor valor), &lt;strong&gt;BOB&lt;/strong&gt; → ODROID XU4 (melhor equilíbrio).&lt;/li&gt;
&lt;li&gt;O próprio site pede pra pegar os dados &amp;quot;com uma colher de sal cheia&amp;quot;: testa só o primeiro e o último core do SoC, sem considerar multithreading nem arquitetura 64-bit. Boards high-end saem prejudicados.&lt;/li&gt;
&lt;li&gt;Benchmark rodado via NEMS Linux; dá pra reproduzir com o script cat5tv-sbctest.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Mini-PC com Intel N100/N97&lt;/h3&gt;
&lt;p&gt;E aqui o motivo de eu não querer um RPI novo no meu cluster, hoje não vale mais a pena, depois de algumas (3) aumentos de preço por conta da crise das memórias, o preço do Rasp no Brasil chegou próximo a alguns Mini-PCs e simplesmente não vale a pena. Você não pode ter um pc na palma da mão que vá competir com um PC, mesmo que ele seja MINI.&lt;/p&gt;
&lt;p&gt;Minha escolha nesse momento está entre o N100 e o N97 e simplemente porque não dá pra comparar com o RPI 5...&lt;/p&gt;
&lt;p&gt;Antes de ir pros benchmarks, uma tabela rápida com o que interessa nos dois:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;N100&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;N97&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Núcleos/threads&lt;/td&gt;
&lt;td&gt;4 / 4 (sem HT)&lt;/td&gt;
&lt;td&gt;4 / 4 (sem HT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clock base / boost&lt;/td&gt;
&lt;td&gt;0,8 / 3,4 GHz&lt;/td&gt;
&lt;td&gt;2,0 / 3,6 GHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TDP&lt;/td&gt;
&lt;td&gt;6W&lt;/td&gt;
&lt;td&gt;12W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache L3&lt;/td&gt;
&lt;td&gt;6 MB&lt;/td&gt;
&lt;td&gt;6 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Litografia&lt;/td&gt;
&lt;td&gt;Intel 7 (10nm)&lt;/td&gt;
&lt;td&gt;Intel 7 (10nm)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memória&lt;/td&gt;
&lt;td&gt;DDR4-3200 ou DDR5-4800, single-channel, até 16GB oficial&lt;/td&gt;
&lt;td&gt;idem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iGPU&lt;/td&gt;
&lt;td&gt;UHD 24 EUs @ 750 MHz&lt;/td&gt;
&lt;td&gt;UHD 24 EUs @ 1.200 MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCIe&lt;/td&gt;
&lt;td&gt;9 lanes 3.0&lt;/td&gt;
&lt;td&gt;9 lanes 3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Geekbench 6 (single/multi)&lt;/td&gt;
&lt;td&gt;~1.200 / ~3.300&lt;/td&gt;
&lt;td&gt;~1.300 / ~3.500-4.500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;O detalhe que quase ninguém comenta: memória &lt;strong&gt;single-channel&lt;/strong&gt;, limita banda pra cerca de metade do que seria dual-channel. Em workloads memory-bound (bancos pesados, ML), você sente.&lt;/p&gt;
&lt;p&gt;Na potência bruta de CPU, o N100 abre uma vantagem consistente de 1,5 a 2× sobre o Pi 5. Em Geekbench 6, o N100 gira em torno de 1.226 single-core e 3.345 multi-core, contra cerca de 837 e 1.711 do Pi 5, quase o dobro no multi-core. A diferença vem de arquitetura e clock: os quatro núcleos Gracemont (Alder Lake-N) do N100 fazem boost até 3,4 GHz e têm IPC próximo ao de um Skylake, enquanto os Cortex-A76 do Pi 5 travam em 2,4 GHz. Em testes onde o x86 tem instruções dedicadas (compressão de dados e, principalmente, criptografia AES), o N100 pode chegar a 8× mais rápido quando o binário ARM é mal otimizado; quando o binário aproveita as Crypto Extensions do Cortex-A76 (que o Pi 5 tem), a diferença cai pra 2-3×. Nos benchmarks do Jeff Geerling, mesmo um N100/N150 com RAM DDR4 mais lenta e refrigeração precária ainda bateu o Pi 5 em 1,5 a 2× no mundo real.&lt;/p&gt;
&lt;p&gt;Mas &amp;quot;injusto&amp;quot; é a palavra certa, porque eles não jogam o mesmo jogo. O N100 traz o que o Pi não tem: 16GB de RAM (contra 8GB), PCIe 3.0 x2 nativo pra NVMe (contra o único lane PCIe 2.0 do Pi via HAT), Quick Sync pra encode/decode de vídeo por hardware, e roda Windows ou qualquer Linux x86 sem asterisco. O Pi 5 revida onde importa pro maker: header GPIO de 40 pinos integrado, conectores de câmera/display, consumo ocioso menor, tamanho de cartão de crédito e um ecossistema de mais de uma década de tutoriais. Curiosidade que quebra o senso comum: apesar de usar um nó de fabricação mais moderno (Intel 7, 10nm) contra o 16nm do Pi, o N100 entrega &lt;em&gt;menos&lt;/em&gt; trabalho por watt, ou seja, &amp;quot;nó melhor = mais eficiente&amp;quot; não é lei universal. No fim, o N100 é um mini PC de verdade que custa quase o mesmo que o o Pi 5, que é mais uma plataforma pra construir. A comparação de potência dá o N100 fácil, mas ela mede a régua errada pra metade dos casos de uso do Pi.&lt;/p&gt;
&lt;p&gt;No fim das contas, para o meu homelab, se eu fosse comprar hoje, o Raspberry PI 5 não vale a pena, porque os diferenciais dele não são interessantes pra mim, simples assim.&lt;/p&gt;
&lt;h3&gt;Notebook ou desktop parado em casa&lt;/h3&gt;
&lt;p&gt;Antes de gastar em SBC ou mini-PC, olha pra estante. O notebook aposentado, o desktop que virou peso de papel, o gamer que você trocou faz um tempo... tudo isso roda Linux, roda Docker, sobe Swarm sem drama. E é x86, então o asterisco do ARM nem aparece.&lt;/p&gt;
&lt;p&gt;Notebook tem um bônus que quase ninguém pensa: a bateria é um no-break de graça. Faltou luz? O cluster continua de pé enquanto o resto da casa apaga. E vem com teclado e tela embutidos pra hora do desespero, quando o SSH não sobe e você precisa plugar um monitor. O custo é o espaço, o consumo maior que um SBC, e a bateria que vai inchar depois de alguns anos ligada 24/7.&lt;/p&gt;
&lt;p&gt;Desktop é o oposto do Pi: espaço e energia à vontade em troca de folga real. Se você tem uma torre parada com 32GB de RAM e uns TB de SSD, você já tem mais recurso do que qualquer mini-PC N100 consegue entregar. A pegadinha vem na fatura de luz, desktop comum idle chega a chupar 40, 50W. E é justamente disso que a gente fala mais abaixo.&lt;/p&gt;
&lt;p&gt;A real na hora de montar o seu homelab é que o melhor hardware pra começar é o que você JÁ TEM. Antes de gastar, olha pra garagem, depois passa pelos 3 guias que eu mostro logo abaixo e vê se o que você tem já resolve.&lt;/p&gt;
&lt;h2&gt;A comparação que importa pro seu homelab&lt;/h2&gt;
&lt;p&gt;Depois de olhar SBC, mini-PC, notebook e desktop, você vai ficar com a mesma pergunta na cabeça: como comparar coisas TÃO diferentes na hora de decidir? Eu resumo em 3 filtros que se complementam: performance bruta, performance por watt, e adequação ao workload.&lt;/p&gt;
&lt;h3&gt;Antes dos 3 filtros: ARM ou x86?&lt;/h3&gt;
&lt;p&gt;Esse é o asterisco do Pi que ninguém comenta com franqueza. Hoje uns 95% das imagens Docker oficiais têm build ARM64 e sobem no Pi sem você nem perceber. O problema são os 5% que faltam, e as vezes é o que dá vontade de usar: uma ferramenta de nicho, um binário proprietário, aquele projetinho legal que o dev só compilou pra amd64.&lt;/p&gt;
&lt;p&gt;No x86 essa dúvida não existe. Você nunca vai abrir um README e ler &amp;quot;ARM não suportado&amp;quot;. Tranquilidade que tem valor, principalmente se você não quer virar refém de checar arquitetura antes de cada deploy. Se você já sabe que ARM te serve, segue reto. Se ficou com dúvida, tem uma seção logo abaixo ensinando como checar antes de comprar.&lt;/p&gt;
&lt;h3&gt;Filtro A: Geekbench 6 (o quão forte é)&lt;/h3&gt;
&lt;p&gt;Para medir o poder do seu hardware, uma dica é usar o &lt;a href=&quot;https://browser.geekbench.com&quot;&gt;Geekbench 6&lt;/a&gt;. Ele é cross-platform (roda em ARM, x86 e ambos), então dá pra comparar um Pi com um mini-PC ou notebook direto, na mesma régua. Você busca pelo modelo do CPU que tá considerando, olha os dois números (single-core e multi-core) e compara. Referência rápida que eu já montei pra você:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pi 5 8GB → ~837 / ~1.711&lt;/li&gt;
&lt;li&gt;Intel N100 → ~1.200 / ~3.300&lt;/li&gt;
&lt;li&gt;Intel N97 → ~1.300 / ~3.500-4.500&lt;/li&gt;
&lt;li&gt;Notebook Intel i5 dos últimos 5 anos → faixa ~900-1.500 / ~2.500-5.500&lt;/li&gt;
&lt;li&gt;Notebook AMD Ryzen 5 recente → chega perto ou passa dos N100/N97&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Regra prática: se o CPU que você mira tem multi-core PRÓXIMO ou MAIOR que o Pi 5 (~1.700), roda tudo que eu rodo nos meus dois Pis. Se é menor, talvez ainda rode, mas você pode sentir gargalo nos picos, testa aí.&lt;/p&gt;
&lt;h3&gt;Filtro B: Performance por watt (o quanto vai custar)&lt;/h3&gt;
&lt;p&gt;O homelab fica ligado 24/7, isso muda o jogo. Um gamer não pensa nisso porque desliga o PC de noite (as vezes haha), homelab não. E a fórmula é simples:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;perf_por_watt = multi_core_score ÷ watts_idle
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O &lt;code&gt;multi_core_score&lt;/code&gt; é aquele segundo número do Geekbench que a gente viu no filtro anterior (o depois da barra). O &lt;code&gt;watts_idle&lt;/code&gt; é o consumo em idle (parado) do teu candidato, aqui vai uma referência confirmada por categoria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pi 5 → 3-3,6W&lt;/li&gt;
&lt;li&gt;N100 → 7,5-10W&lt;/li&gt;
&lt;li&gt;N97 → ~9-10W&lt;/li&gt;
&lt;li&gt;Notebook → 5-15W (varia MUITO por geração)&lt;/li&gt;
&lt;li&gt;Desktop → 25-60W (mesmo idle)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Você SEMPRE pode pesquisar consumo em idle do seu hardware na internet ou etiqueta na caixa ou no próprio hardware.&lt;/p&gt;
&lt;p&gt;Rodando a fórmula com os números do meio da faixa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pi 5 → ~518 pts/W 🥇&lt;/li&gt;
&lt;li&gt;N97 → ~400 pts/W 🥈&lt;/li&gt;
&lt;li&gt;N100 → ~367 pts/W 🥉&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pi 5 ainda ganha em eficiência, mas por MENOS do que a fama diz, cerca de 40% a mais que os N. Só que em performance bruta o N devolve o dobro. Escolha clássica de homelab: barato de operar e fraco, ou caro de operar e forte. Não tem almoço grátis.&lt;/p&gt;
&lt;p&gt;Para calcular o valor em Reais de consumo de energia, você pode usar a seguinte fórmula:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kWh no ano   = (watts × 24 × 365) ÷ 1000
Custo no ano = kWh × (sua tarifa por kWh)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sua tarifa tá na conta de luz, procura por &amp;quot;R$/kWh&amp;quot;. Multiplica pelos watts de cada opção e você tem o custo REAL de operar por ano.&lt;/p&gt;
&lt;h3&gt;Filtro C: Workload (serve pra QUE)&lt;/h3&gt;
&lt;p&gt;Score alto não ajuda em nada se não é o que você precisa. Casos que aparecem no homelab de verdade:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Serviços leves idle&lt;/strong&gt; (Traefik, Gitea, Pi-hole, Vaultwarden) → qualquer coisa serve. Até Pi 4 ou 3 rodava.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Muitos containers idle&lt;/strong&gt; (30-60, tipo o meu setup) → RAM importa MUITO mais que CPU. 16GB total é o mínimo confortável.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jellyfin com transcoding&lt;/strong&gt; → precisa Quick Sync (Intel) ou GPU dedicada. Pi 5 sofre aqui.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bancos pesados&lt;/strong&gt; (Postgres, Mongo com carga real) → I/O rápido (NVMe) e RAM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LLM local&lt;/strong&gt; → GPU + muita RAM. Nenhum SBC ou N100 entrega, é desktop com placa de vídeo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compilação/CI pesada&lt;/strong&gt; → CPU multi-core forte. N100/N97 já sofre, precisa mini-PC N305 ou desktop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Juntando os 3 filtros&lt;/h3&gt;
&lt;p&gt;Consumo importa mais que tudo? Vai de Pi 5 (confere se o valor vale a pena).
Preço-performance importa mais? Vai de mini-PC N100 ou N97.
Já tem hardware parado em casa? Começa por ele.
Workload é pesado (LLM, transcoding, CI)? Vai de desktop com hardware dedicado.&lt;/p&gt;
&lt;p&gt;Não existe &amp;quot;resposta certa&amp;quot;, existe a que fecha a conta PRO SEU CASO... e agora você tem os 3 filtros pra fazer essa conta com propriedade.&lt;/p&gt;
&lt;h2&gt;A pegadinha do ARM (que ninguém te conta)&lt;/h2&gt;
&lt;p&gt;A boa notícia: dá pra saber ANTES de comprar (ou antes de perder uma tarde) se uma imagem roda no seu Pi. O comando mágico é o &lt;code&gt;docker manifest inspect&lt;/code&gt;, que mostra pra quais arquiteturas aquela imagem foi publicada:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker manifest inspect grafana/grafana | grep architecture
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se aparecer &lt;code&gt;arm64&lt;/code&gt; (ou &lt;code&gt;aarch64&lt;/code&gt;) na lista, tá suportado. Se só aparecer &lt;code&gt;amd64&lt;/code&gt;, esquece, no Pi ela não sobe, ou sobe emulada e lentíssima. Faz esse teste com os 4 ou 5 serviços que são o CORAÇÃO do teu homelab antes de decidir a arquitetura. Se todos passarem, ARM é seguro pra você. Se um dos essenciais falhar, ou você troca de ferramenta, ou já sabe que vai precisar de um nó x86 no meio do cluster.&lt;/p&gt;
&lt;p&gt;Os suspeitos de sempre que ainda te obrigam ao x86: alguns produtos comerciais que só distribuem binário amd64, ferramentas antigas sem manutenção, e vez ou outra algo de machine learning que depende de instrução específica. Fora esses, ARM em 2026 é MUITO mais tranquilo do que a fama sugere.&lt;/p&gt;
&lt;h2&gt;Casos reais: qual hardware pra qual situação&lt;/h2&gt;
&lt;p&gt;Chega de &amp;quot;depende&amp;quot;. Vou cravar recomendação pra cada cenário, se o seu caso for parecido, segue a seta:&lt;/p&gt;
&lt;h3&gt;&amp;quot;Quero rodar 5-15 services em casa, com baixo consumo&amp;quot;&lt;/h3&gt;
&lt;p&gt;-&amp;gt; Raspberry Pi 5 8GB. É exatamente o sweet spot dele: consumo ridículo, silencioso, dá conta folgado dessa carga e você ainda aprende ARM de brinde. Não complica.&lt;/p&gt;
&lt;h3&gt;&amp;quot;Quero rodar 30+ services com bancos pesados&amp;quot;&lt;/h3&gt;
&lt;p&gt;-&amp;gt; Mini-PC N100 (16GB) ou 2× Pi 5 em cluster. &amp;quot;Banco pesado&amp;quot; é a palavra-chave: aí RAM e CPU passam a importar e o N100 entrega. Se você quer o desafio (e o aprendizado) de distribuir carga, dois Pis em cluster também seguram, foi o caminho que eu escolhi.&lt;/p&gt;
&lt;h3&gt;&amp;quot;Quero o melhor desempenho por R$&amp;quot;&lt;/h3&gt;
&lt;p&gt;-&amp;gt; Mini-PC N100 com 16GB. Com o preço do Pi lá nas alturas, o N100 entrega o dobro de performance, o dobro de RAM e já vem completo. Hoje, custo-benefício puro, é ele. Sem drama.&lt;/p&gt;
&lt;h3&gt;&amp;quot;Quero aprender DevOps de verdade&amp;quot;&lt;/h3&gt;
&lt;p&gt;-&amp;gt; Cluster de 2 Pis. Aqui a &amp;quot;ineficiência&amp;quot; é o ponto: lidar com ARM, montar NFS compartilhado, quebrar a cabeça com cluster de verdade... ISSO é o aprendizado. Se o objetivo é o currículo e a experiência, o caminho mais chato é o mais valioso.&lt;/p&gt;
&lt;h2&gt;Como eu decidi (POV)&lt;/h2&gt;
&lt;p&gt;Vou contar a real, sem verniz. Eu queria duas coisas: baixo consumo de energia e botar a mão em ARM de propósito, pra aprender apanhando. Por isso fui de Raspberry Pi 5 8GB e montei um cluster com dois deles, NFS compartilhado entre os nós, e hoje roda mais de 60 serviços ali dentro, MUITA coisa que eu de fato uso no dia a dia.&lt;/p&gt;
&lt;p&gt;Funciona? Funciona, e bem. Mas seria desonesto não contar o revés: o preço do Pi 5 DISPAROU. Eu só tenho dois nós porque, quando fui comprar o terceiro, o preço tinha triplicado, culpa da crise das memórias e da IA sugando tudo. O sonho do cluster maior travou na fatura, não na tecnologia.&lt;/p&gt;
&lt;p&gt;O que eu faria diferente hoje? Se fosse começar do zero, com os preços atuais, provavelmente iria de mini-PC N100. Não porque o Pi ficou ruim (ele tá ótimo), mas porque a conta mudou. O diferencial do Pi (tamanho, GPIO, consumo mínimo) não é o que EU preciso, e pagar quase o mesmo por menos performance deixou de fazer sentido. Já tenho meus dois Pis, gosto deles, vou levar até o fim. Mas o próximo nó, se vier, provavelmente é x86.&lt;/p&gt;
&lt;h2&gt;Perguntas frequentes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Vale começar com Pi 4 (mais barato) hoje?&lt;/strong&gt;
Vale se ele caiu de graça no teu colo. Comprando novo, hoje o Pi 4 não compensa: você perde USB 3.0 real, gigabit real e o RP1 do Pi 5. A economia sobre o Pi 5 8GB ficou pequena demais pra abrir mão dessas melhorias.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4GB ou 8GB de RAM no Pi 5?&lt;/strong&gt;
8GB. Sempre. RAM é o primeiro recurso que aperta num homelab, e a memória do Pi é soldada, sem upgrade depois. Compra com folga de uma vez.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Posso misturar Pi (ARM) e mini-PC (x86) no mesmo Swarm?&lt;/strong&gt;
Pode. Docker lida com imagens multi-arch, Swarm agenda nos nós certos. Pegadinha: imagens só-amd64 não rodam no Pi. Ou você fixa esses serviços no nó x86 com constraints, ou garante que tudo é multi-arch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;N100 vs N97 vs N305: qual escolher?&lt;/strong&gt;
N100 é o sweet spot (mais oferta, mais barato). N97 é levemente mais rápido, mas oferta menor. N305 são oito núcleos, esquenta mais e vira overkill pra homelab pessoal, só faz sentido se você VAI saturar de verdade. Na dúvida, N100.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E o Orange Pi / Banana Pi / Rock Pi?&lt;/strong&gt;
Mais baratos e às vezes mais fortes no papel, mas o calcanhar de Aquiles é o suporte de SO e drivers. Você troca dinheiro por paciência de debug. Vale se você curte o processo e não tem pressa; não vale se você quer a coisa no ar hoje com tutorial pronto.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E se eu tiver notebook ou desktop velho parado em casa?&lt;/strong&gt;
Usa. O melhor hardware pra começar homelab é o que já tá em casa. Roda os 3 filtros (A, B, C) com o modelo que você tem, se aguenta seu workload, comprar hardware novo é procrastinar. Presta atenção só na fatura de luz do desktop antigo, que é onde ele te pega.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Onde eu pesquiso o Geekbench do meu CPU?&lt;/strong&gt;
&lt;a href=&quot;https://browser.geekbench.com&quot;&gt;browser.geekbench.com&lt;/a&gt;, busca pelo nome do processador. Se o multi-core aparece próximo ou maior que 1.700, roda tudo que eu rodo no meu cluster de 2 Pis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Notebook 24/7 não estraga a bateria?&lt;/strong&gt;
Estraga sim, e você precisa saber disso. Depois de 1-2 anos ligado full-time a bateria incha. Duas opções: aceita e troca a bateria quando morrer (é peça barata), ou remove ela e roda direto do carregador (alguns modelos permitem). Se remover, adeus no-break, cada escolha tem custo.&lt;/p&gt;
&lt;h2&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Não existe hardware &amp;quot;certo&amp;quot;, existe o certo PRA VOCÊ: Pi 5 se o que pesa é consumo e ARM, mini-PC N100 se o que pesa é performance por real, e o desktop ou notebook parado na garagem se o que pesa é começar HOJE gastando zero. Faça as contas com as fórmulas que deixei aqui, com os preços do dia em que você tá lendo, e decida com propriedade, a receita é sua, não minha.&lt;/p&gt;
&lt;p&gt;Decidiu o hardware? O próximo passo é escolher o orquestrador que vai rodar em cima dele, e é disso que trata o guia abaixo.&lt;/p&gt;
&lt;!-- TODO: trocar pelo link real do pillar quando publicar --&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.erikfigueiredo.com.br/posts/raspberry-pi-mini-pc-ou-desktop-hardware-homelab/&quot;&gt;guia completo de homelab DevOps com stack self-hosted&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Docker Swarm vs Kubernetes no homelab: qual escolher em 2026</title>
    <link href="https://blog.erikfigueiredo.com.br/posts/docker-swarm-vs-kubernetes-homelab-qual-escolher-2026/" />
    <updated>2026-06-19T00:00:00Z</updated>
    <id>https://blog.erikfigueiredo.com.br/posts/docker-swarm-vs-kubernetes-homelab-qual-escolher-2026/</id>
    <content type="html">&lt;div class=&quot;cover-image&quot;&gt;
  &lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blog.erikfigueiredo.com.br/img/bl3sBlhr0e-1200.webp 1200w&quot;&gt;&lt;img src=&quot;https://blog.erikfigueiredo.com.br/img/bl3sBlhr0e-1200.jpeg&quot; alt=&quot;Capa do artigo: Docker Swarm vs Kubernetes no homelab — qual escolher em 2026&quot; width=&quot;1200&quot; height=&quot;800&quot; loading=&quot;lazy&quot;&gt;&lt;/picture&gt;
&lt;/div&gt;
&lt;p&gt;Pra rodar serviços em casa, &lt;strong&gt;Docker Swarm vence Kubernetes na maioria dos casos&lt;/strong&gt;: a curva de aprendizado é uma fração da do K8s, consome muito menos RAM, gerencia stacks com um &lt;code&gt;docker stack deploy&lt;/code&gt;, e não exige cluster control plane separado. Kubernetes só compensa no homelab se o objetivo é &lt;strong&gt;aprender K8s pro trabalho&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker Swarm tem curva ~1/10 da do Kubernetes pra colocar um serviço no ar.&lt;/li&gt;
&lt;li&gt;Roda confortável em Raspberry Pi; K8s puro em homelab pede 3+ nodes parrudos.&lt;/li&gt;
&lt;li&gt;Stacks reaproveitam o &lt;code&gt;docker-compose.yml&lt;/code&gt; que você já conhece.&lt;/li&gt;
&lt;li&gt;K8s só vale se o objetivo é aprender K8s — não pra rodar self-hosted em casa.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Um projeto que tenho trabalhado com muito afinco nos últimos tempos é na construção do meu homelab, ainda sonho com um setup elaborado, capaz de rodar uma llm forte e ter acesso e muito espaço em disco e uma GPU poderosa pra todo o tipo de processamento, mas o que tenho hoje já é bem interessante pra mim, mas claro, estou DIVAGANDO.&lt;/p&gt;
&lt;p&gt;O grande ponto aqui é porque eu tomei a INSANA decisão de escolher o Swarm ao Kubernetes.&lt;/p&gt;
&lt;h2&gt;O que é o Docker Swarm&lt;/h2&gt;
&lt;p&gt;O Docker Swarm é uma ferramenta nativa do Docker focada em orquestração de containers, agrupando multiplos servidores (físicos ou virtuais) em um cluster distribuído.&lt;/p&gt;
&lt;p&gt;Na prática, ele gerencia os seus containers, replica em um ou vários servidores e mantém um serviço no ar mesmo se o serviço crashar e cair, subindo de novo.&lt;/p&gt;
&lt;p&gt;A maior vantagem dele é já vir junto do Docker nativamente (dispensando instalações externas) e você poder usar seu próprio docker-compose.yml para configurá-lo, já que as configs adicionais do yaml apenas são ignoradas pelo Docker Compose.&lt;/p&gt;
&lt;p&gt;A desvantagem óbvia é que ele é demasiadamente simples perto do poder do K8s e isso somando ao fato do investimento que a própria Docker faz no Kubernetes ao invés de apostar na ferramenta nativa o torna o irmão menor que ninguém quer brincar.&lt;/p&gt;
&lt;p&gt;Mas não subestimem o Swarm, ele tem seu valor.&lt;/p&gt;
&lt;h2&gt;O que é Kubernetes&lt;/h2&gt;
&lt;p&gt;O Kubernetes (ou K8s — o 8 representa as 8 letras entre K e s, &lt;em&gt;ubernete&lt;/em&gt;) é o CARA! Assim como o Swarm, ele gerencia multiplos servidores, orquestra os containers para melhor aproveitamento dos recursos do servidor, e mantendo os pods (seus serviços em containers) saudáveis (disponíveis).&lt;/p&gt;
&lt;p&gt;Na prática, ele é claramente superior ao Swarm, tem autoscaling real, extensibilidade maior, storage avançado, rede e segurança MUITO superiores, observabilidade e scheduling... tudo é superior! Não tem o que discutir. Além de ser open-source e ter uma comunidade MUITO maior. Fato! É superior e PRONTO!&lt;/p&gt;
&lt;p&gt;Claro que tudo isso tem um preço e a desvantagem óbvia é que ele é mais pesado, mais complexo de usar e... desnecessário!&lt;/p&gt;
&lt;p&gt;Não num contexto geral, desnecessário no meu contexto... Eu usaria ele simplesmente para o que já uso o Swarm, manter meus containers UP e distribuidos entre os diferentes nós (cada servidor é um nó).&lt;/p&gt;
&lt;h2&gt;O Docker Swarm está morrendo?&lt;/h2&gt;
&lt;p&gt;Pra começar, vale relembrar do Docker Swarm original, que realmente foi descontinuado lá em meados de 2015/2016. Esse cara morreu mesmo, ele era uma ferramenta a parte do Docker. Em seu lugar surgiu o Swarm mode que usamos hoje, parte do Docker principal.&lt;/p&gt;
&lt;p&gt;Quando te disserem que o Swarm morreu, bem... não estão inteiramente errados ou mentindo, esse &amp;quot;Docker standalone&amp;quot; realmente morreu!&lt;/p&gt;
&lt;p&gt;Em 2017 a Mirantis comprou a Docker Enterprise e anunciou que o Kubernetes seria o orquestrador principal daqui pra frente, eu não lembro bem se existiu um anúncio real ou se foi &amp;quot;hype da comunidade&amp;quot;, mas a conversa que rolava na internet é que o Swarm morreria em 2 anos e o K8s era o caminho, muita gente &amp;quot;abandonou o barco&amp;quot; e foi pro K8s definitivamente, inclusive este que vos escreve!&lt;/p&gt;
&lt;p&gt;O que eu lembro bem foi que em 2020 a Mirantis anunciou que o suporte ao Swarm continuaria e que, em levantamento deles, existiam MUITOS servidores rodando o Swarm, que novos recursos chegariam com o tempo, além de manutenção e correção de segurança.&lt;/p&gt;
&lt;p&gt;Muita gente usava o Swarm e o Kubernetes em conjunto, o primeiro em clusters pequenos e simples (já que, como bem sabemos, ser pequeno é MUITO diferente de ser simples, minha esposa que o diga).&lt;/p&gt;
&lt;p&gt;A Mirantis anunciou em 2025 que o suporte ao Swarm vai se estender por mais 5 anos (2030) e garantiu que a orquestração simplificada dele tenha um novo respiro.&lt;/p&gt;
&lt;p&gt;Além disso, ele recebeu suporte a CSI (Container Storage Interface), constraints de recursos e outros itens de roadmap, tirando o Swarm do limbo de &amp;quot;só manutenção&amp;quot;.&lt;/p&gt;
&lt;p&gt;O ponto mais forte de todos é que a própria comunidade em volta dos orquestradores de containers vem discutindo a real vantagem do K8s, que a única feature real que ele tem sobre o Swarm é o autoscaling e que o resto só é mais parrudo e isso ainda cobra o preço em cima da performance (não necessariamente concordo com tudo, tá...).&lt;/p&gt;
&lt;p&gt;Minha opinião real é que eu acho que o K8s é mais poderoso que o Swarm sim e tudo bem, não faz o Swarm menos necessário no contexto geral, ele é uma forma SIMPLES de orquestrar containers... as vezes é só o que precisamos.&lt;/p&gt;
&lt;p&gt;Eu trabalho com PHP desde 2 mil e não quero falar quanto... e desde o primeiro dia dizem que ele vai morrer, de verdade, não acredito nisso de que é fácil de matar uma tecnologia. Vida longa ao Swarm!&lt;/p&gt;
&lt;h2&gt;Por que escolhi o Swarm no meu cluster?&lt;/h2&gt;
&lt;p&gt;Se fosse pra resumir tudo em uma palavra? Eu diria SIMPLICIDADE!&lt;/p&gt;
&lt;p&gt;O Docker Swarm é simples de usar, tem uma curva de aprendizado menor, menos problemas pra lidar e já estava disponível.&lt;/p&gt;
&lt;p&gt;Eu tomei a decisão consciente de montar um cluster de Raspberry PIs 5 8gb (Raspberrie PIs, Raspberrys PIs... como é o plural disso?), queria baixo custo de energia e lidar com ARM, mas dai é assunto pra outro dia... o fato é que eles não são lá muito fortes e eu só tenho 2 (depois que comprei o preço disparou).&lt;/p&gt;
&lt;p&gt;Somando esse cenário eu comecei a escrever os arquivos de configuração para o K3s...&lt;/p&gt;
&lt;p&gt;Pera... K3s? Daonde isso apareceu?&lt;/p&gt;
&lt;p&gt;É... além do K8s (Kubernetes) temos o K3s, ele é o irmão do meio e uma opção sólida ao Kubernetes.&lt;/p&gt;
&lt;p&gt;O K3s é o Kubernetes da Rancher/SUSE e uma excelente opção ao Swarm, tem bom suporte a ARM, é só componentes e runtime do K8s, bem leve mesmo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Inclusive o nome K3s é uma brincadeira com ele ser metade do K8s (5 letras a menos).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ele ocupa o mesmo lugar do Swarm (eu considero um concorrente real, o K8s não concorre com o Swarm, são para fins distintos), mesmo que o Swarm ainda consuma MUITO menos que o K3s (convenhamos, o Swarm sai de graça rodando em cima do Docker, não dá pra competir).&lt;/p&gt;
&lt;p&gt;Então eu pensei muito, e se meu homelab crescer? Talvez um servidor parrudo de verdade... migrar do Swarm pro Kubernetes é uma coisa extremamente chata de fazer (&amp;quot;Claude, migra meus serviços do swarm pro k8s e não cometa erros&amp;quot;), o K3s tem a mesma API, e isso quer dizer ZERO reescrita de arquivos de configuração. É um ponto válido!&lt;/p&gt;
&lt;p&gt;No fim eu fui pela simplicidade do Swarm, menos coisas pra escrever, mais simples de gerar um template pra IA alterar depois e ainda tem a realidade da minha vida:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Meu trabalho&lt;/li&gt;
&lt;li&gt;Subir serviços rapidamente no homelab (ainda vou recomendar alguns serviços self-hosted aqui)&lt;/li&gt;
&lt;li&gt;Criar meus projetinhos do zero&lt;/li&gt;
&lt;li&gt;Família&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quanto menos eu tiver que escrever ou me preocupar, MELHOR. O Kubernetes é bem verboso, o Swarm tem meia dúzia de opções a mais (e opcionais) no Docker Compose e ainda tem o gancho: Swarm já está lá, ele vem com o Docker.&lt;/p&gt;
&lt;p&gt;Com esse pensamento o Swarm ficou óbvio, eu já vou escrever o docker-compose.yml pra testar tudo antes do deploy, então porque não aproveitar isso num primeiro momento e depois eu migro.&lt;/p&gt;
&lt;p&gt;Nada como uma promessa de melhoria futura ou uma gambiarra temporária... não que o Swarm seja gambiarra, não foi o que eu quis dizer.&lt;/p&gt;
&lt;p&gt;No fim eu fiquei com o Swarm mesmo, tenho um cluster com (atualmente) pouco mais de 50 services rodando com MUITA coisa que eu preciso.&lt;/p&gt;
&lt;p&gt;Para o futuro, não sei se escapo, o Swarm caminha devagar, meio-morto e meio-vivo (um vampiro praticamente), o K3s vai vir em algum tempo, provavelmente, mas não vou matar a tecnologia ANTES da hora.&lt;/p&gt;
&lt;h2&gt;A estrada até aqui&lt;/h2&gt;
&lt;p&gt;&amp;quot;Carry on, my wayward son
There&#39;ll be peace when you are done
Lay your weary head to rest
Don&#39;t you cry no more&amp;quot;&lt;/p&gt;
&lt;p&gt;A verdade é que eu sou zero desapego com &amp;quot;modinha&amp;quot;, tanto que nem sei o que é modinha atualmente, mas com foco REAL no que eu preciso:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preciso distribuir meus serviços entre 2 PI5&lt;/li&gt;
&lt;li&gt;Não preciso gastar alguns megas a mais pra fazer isso&lt;/li&gt;
&lt;li&gt;Não preciso da complexidade das configurações do Kubernetes&lt;/li&gt;
&lt;li&gt;Não preciso dos recursos adicionais do Kubernetes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pra que usar algo que traz recursos que eu NÃO PRECISO e me cobra por isso em desempenho? Não faz sentido, mesmo que ele morra em 5 anos... nem sei se os Raspberrys duram tanto... não sei nem se eu duro.&lt;/p&gt;
&lt;p&gt;Se o foco fosse currículo, certeza que eu ia de K3s.&lt;/p&gt;
&lt;p&gt;E isso fecha minha análise sobre porque eu decidi pelo Swarm ao K8S... vamos de um tutorialzinho pra colocar um serviço UP em ambos os orquestradores?&lt;/p&gt;
&lt;h2&gt;Como subir um serviço no Swarm e no Kubernetes&lt;/h2&gt;
&lt;p&gt;Chega de papo, bora pôr a mão na massa. A ideia aqui é a mais simples possível: subir um &amp;quot;Olá, mundo!&amp;quot; nos dois orquestradores e sentir na prática a diferença de cerimônia entre eles.&lt;/p&gt;
&lt;p&gt;Não vou abordar instalação, primeiro que eu confio na sua capacidade, segundo que o Swarm já deve estar instalado aí, né?&lt;/p&gt;
&lt;p&gt;Primeiro a gente cria um app bem bobo só pra ter o que subir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// app.js
require(&amp;quot;http&amp;quot;).createServer((_, res) =&amp;gt; res.end(&amp;quot;Olá, mundo!&amp;quot;)).listen(3000);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Um servidor HTTP que responde na porta 3000 e olhe lá. Agora o Dockerfile pra empacotar isso numa imagem:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;# Dockerfile
FROM node:alpine
COPY app.js .
CMD [&amp;quot;node&amp;quot;, &amp;quot;app.js&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E construímos a imagem. Esse passo é comum aos dois orquestradores, então faz uma vez só:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker build -t hello-node .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pronto, agora temos uma imagem &lt;code&gt;hello-node&lt;/code&gt; na engine do Docker. É a partir daqui que os caminhos se separam.&lt;/p&gt;
&lt;h2&gt;Subindo no Swarm&lt;/h2&gt;
&lt;p&gt;O arquivo de configuração do Swarm eu vou chamar de &lt;code&gt;stack.yml&lt;/code&gt;, por convenção:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &amp;quot;3.8&amp;quot;
services:
  hello:
    image: hello-node
    ports:
      - &amp;quot;3000:3000&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se isso te parece um &lt;code&gt;docker-compose.yml&lt;/code&gt;, é porque é EXATAMENTE isso. É o mesmo arquivo que você já escreveria pra testar localmente, e esse é o pulo do gato do Swarm que eu tanto falei lá em cima.&lt;/p&gt;
&lt;p&gt;Pra subir são dois comandos:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker swarm init                      # só na 1ª vez, ativa o modo swarm
docker stack deploy -c stack.yml hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O &lt;code&gt;docker swarm init&lt;/code&gt; você roda uma vez só, é o que liga o modo swarm na máquina. O &lt;code&gt;stack deploy&lt;/code&gt; é o que de fato sobe o serviço.&lt;/p&gt;
&lt;p&gt;Isso quer dizer que agora pra subir outros serviços, o swarm init não é mais necessário.&lt;/p&gt;
&lt;p&gt;E... acabou. Acessa em &lt;code&gt;http://localhost:3000&lt;/code&gt; e tá lá o &amp;quot;Olá, mundo!&amp;quot;. Dois comandos úteis pra acompanhar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker stack services hello   # ver o status dos serviços
docker stack rm hello         # derrubar tudo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repara num detalhe: a imagem &lt;code&gt;hello-node&lt;/code&gt; &amp;quot;simplesmente estava lá&amp;quot;. Construí com o Docker, subi com o Docker, mesma engine. Guarda essa observação, porque já já ela faz diferença.&lt;/p&gt;
&lt;h2&gt;Subindo no Kubernetes (k3s)&lt;/h2&gt;
&lt;p&gt;Aqui o arquivo eu vou chamar de &lt;code&gt;hello.yaml&lt;/code&gt;. E olha só o tamanho da diferença:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: hello
          image: hello-node
---
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  type: NodePort
  selector:
    app: hello
  ports:
    - port: 3000
      targetPort: 3000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Onde no Swarm eram 6 linhas, aqui são umas 30. É a mesma intenção — uma imagem, uma porta exposta — mas o Kubernetes te faz declarar separadamente um Deployment (quem gerencia os pods) e um Service (quem expõe a rede). Mais verboso, mais explícito, mais cerimônia.&lt;/p&gt;
&lt;p&gt;Pra subir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo k3s ctr images import &amp;lt;(docker save hello-node)   # leva a imagem local pro containerd do k3s
kubectl apply -f hello.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E é aqui que aparece aquela fricção que eu comentei lá atrás. Olha a primeira linha: por que diabos eu preciso &amp;quot;importar&amp;quot; a imagem?&lt;/p&gt;
&lt;p&gt;Porque o k3s não usa a engine do Docker, ele usa o containerd dele. Então aquela imagem &lt;code&gt;hello-node&lt;/code&gt; que eu construí com o &lt;code&gt;docker build&lt;/code&gt; não &amp;quot;existe&amp;quot; pro cluster — ela tá na engine do Docker, não no containerd do k3s. Se eu pular esse passo, o pod fica eternamente em &lt;code&gt;ErrImagePull&lt;/code&gt;, tentando baixar uma imagem que tá ali do lado mas que ele não enxerga.&lt;/p&gt;
&lt;p&gt;No Swarm isso não acontece porque é a mesma engine que constrói e que orquestra. No k3s eu tenho um passo a mais só pra transportar a imagem de um runtime pro outro. (Em produção &amp;quot;de verdade&amp;quot; você resolve isso subindo um registry, mas aí já é mais uma camada de coisa pra cuidar.)&lt;/p&gt;
&lt;p&gt;Pra acessar e acompanhar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get svc hello          # mostra a porta NodePort sorteada, algo como 3000:31xxx
kubectl get pods               # status dos pods
kubectl delete -f hello.yaml   # derrubar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O &lt;code&gt;get svc&lt;/code&gt; te mostra a porta que o NodePort sorteou (um número alto, tipo &lt;code&gt;31xxx&lt;/code&gt;), e é nela que você acessa: &lt;code&gt;http://localhost:31xxx&lt;/code&gt;. Nem a porta vem redondinha como no Swarm.&lt;/p&gt;
&lt;h2&gt;O veredito da preguiça&lt;/h2&gt;
&lt;p&gt;Põe os dois lado a lado e o contraste fica gritante:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Swarm:&lt;/strong&gt; escreve um compose de 6 linhas, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;deploy&lt;/code&gt;. A imagem local simplesmente está lá. Acaba.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;k3s:&lt;/strong&gt; escreve um manifesto de 30 linhas dividido em Deployment + Service, &lt;code&gt;build&lt;/code&gt;, importa a imagem entre runtimes, &lt;code&gt;apply&lt;/code&gt;, e ainda descobre qual porta foi sorteada.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mesmíssimo &amp;quot;Olá, mundo!&amp;quot;. Mesmíssimo resultado. E o k8s custou mais arquivo pra escrever, mais um runtime pra entender e mais uma etapa de cerimônia.&lt;/p&gt;
&lt;p&gt;Pra um cluster de dois Raspberry Pi rodando os serviços da minha casa? A escolha se escreve sozinha. E é por isso, no fim das contas, que eu fiquei com o Swarm.&lt;/p&gt;
&lt;p&gt;Não é preguiça e não é o K3s, K8s, Kubernetes (ou como você queira chamar) que é pior ou melhor, é o caminho que você quer trilhar, quer chegar onde? Por qual motivo?&lt;/p&gt;
&lt;p&gt;Vai crescer? Quer aprender K8s? Precisa de uma feature que o Swarm não tem? -&amp;gt; Kubernetes.&lt;/p&gt;
&lt;p&gt;Quer simplicidade? Tá entrando agora no mundo da orquestração de containers? -&amp;gt; Vai de Swarm.&lt;/p&gt;
&lt;p&gt;E boa sorte no seu caminho.&lt;/p&gt;
&lt;h2&gt;Perguntas frequentes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Docker Swarm está morto?&lt;/strong&gt;
Não. O Swarm standalone (de 2014) morreu em 2016 com a chegada do Swarm mode integrado ao Docker. A Mirantis confirmou em 2025 que o suporte vai até 2030, com novos recursos como CSI no roadmap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;K3s não resolve o problema do K8s pesado?&lt;/strong&gt;
Resolve metade — fica leve o suficiente pra rodar em ARM, mas ainda traz a curva de aprendizado do Kubernetes. Pra homelab que só precisa orquestrar containers, o Swarm continua mais simples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;É fácil migrar de Swarm pra Kubernetes depois?&lt;/strong&gt;
É chato, mas não impossível. Se você já planeja crescer, K3s evita a migração porque mantém a API do K8s. Se simplicidade é prioridade hoje, Swarm primeiro e migra depois quando precisar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Posso rodar Swarm e Kubernetes no mesmo cluster?&lt;/strong&gt;
Sim, em nós separados (ou VMs separadas). Não dá pra rodar os dois no mesmo nó ao mesmo tempo.&lt;/p&gt;
&lt;!-- TODO: trocar pelo link real do pillar quando publicar --&gt;
&lt;p&gt;Decidiu por Swarm? O próximo passo é montar a stack completa: &lt;a href=&quot;https://blog.erikfigueiredo.com.br/posts/docker-swarm-vs-kubernetes-homelab-qual-escolher-2026/&quot;&gt;guia completo de homelab DevOps com Swarm&lt;/a&gt; — Traefik como ingress, Gitea como source of truth, bancos compartilhados e pipelines de deploy.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Hello World em programação: muito mais que uma frase</title>
    <link href="https://blog.erikfigueiredo.com.br/posts/hello-world-muito-mais-que-uma-frase/" />
    <updated>2025-05-28T00:00:00Z</updated>
    <id>https://blog.erikfigueiredo.com.br/posts/hello-world-muito-mais-que-uma-frase/</id>
    <content type="html">&lt;div class=&quot;cover-image&quot;&gt;
  &lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blog.erikfigueiredo.com.br/img/5BqVfqarOW-1200.webp 1200w&quot;&gt;&lt;img src=&quot;https://blog.erikfigueiredo.com.br/img/5BqVfqarOW-1200.jpeg&quot; alt=&quot;Capa do artigo: Hello World – Muito mais que uma frase&quot; width=&quot;1200&quot; height=&quot;800&quot; loading=&quot;lazy&quot;&gt;&lt;/picture&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Hello, World!&lt;/strong&gt; é o primeiro programa escrito por quem começa a programar — uma frase simples impressa na tela para validar que o ambiente, o compilador e o terminal estão funcionando. Surgiu em 1978 no livro &lt;em&gt;The C Programming Language&lt;/em&gt; de Kernighan e Ritchie, e hoje virou ritual de iniciação em praticamente toda linguagem.&lt;/p&gt;
&lt;p&gt;Todo mundo já viu essa frase: &lt;strong&gt;&amp;quot;Hello, World!&amp;quot;&lt;/strong&gt;&lt;br&gt;
Parece simples, inofensiva, até boba. Mas na verdade, ela representa o primeiro passo em uma jornada que pode mudar sua vida.&lt;/p&gt;
&lt;p&gt;Hoje eu quero falar (ou escrever) tudo o que devia ter escrito no primeiro artigo. Quero começar este blog como começo &lt;strong&gt;toda linguagem de programação que estudei até hoje&lt;/strong&gt;: um ritual.&lt;/p&gt;
&lt;h2&gt;De onde veio o &amp;quot;Hello, World!&amp;quot;?&lt;/h2&gt;
&lt;p&gt;O primeiro registro conhecido dessa frase vem do livro &lt;strong&gt;“The C Programming Language”&lt;/strong&gt;, de Brian Kernighan e Dennis Ritchie, publicado em 1978.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;stdio.h&amp;gt;

int main() {
    printf(&amp;quot;Hello, World!&#92;n&amp;quot;);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Era uma forma simples de testar se tudo estava funcionando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;O compilador&lt;/li&gt;
&lt;li&gt;O terminal&lt;/li&gt;
&lt;li&gt;O código&lt;/li&gt;
&lt;li&gt;A mente do programador 😅&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Por que usamos isso até hoje?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;✅ É o programa mais básico possível&lt;/li&gt;
&lt;li&gt;✅ Não depende de lógica complexa&lt;/li&gt;
&lt;li&gt;✅ Mostra que seu ambiente está funcionando&lt;/li&gt;
&lt;li&gt;✅ Traz &lt;strong&gt;feedback instantâneo&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;✅ Cria &lt;strong&gt;confiança&lt;/strong&gt; no iniciante&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;O poder simbólico do &amp;quot;Hello, World!&amp;quot;&lt;/h2&gt;
&lt;p&gt;Para muitos, esse é o &lt;strong&gt;primeiro contato&lt;/strong&gt; com a criação de algo real.&lt;br&gt;
É o momento em que você escreve algo e a máquina responde.&lt;br&gt;
É o despertar da consciência programadora.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;É o &amp;quot;olá&amp;quot; do criador para o universo digital.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Hello World em diferentes linguagens&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&amp;quot;Hello, World!&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;console.log(&amp;quot;Hello, World!&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;echo &amp;quot;Hello, World!&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo &amp;quot;Hello, World!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;puts &amp;quot;Hello, World!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cada linguagem tem seu jeito, mas todas compartilham da mesma intenção.&lt;/p&gt;
&lt;h2&gt;Muito além do código&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Hello, World!&amp;quot;&lt;/strong&gt; é um marco.&lt;br&gt;
Quando você digita isso pela primeira vez, não está só aprendendo uma linguagem.&lt;br&gt;
Você está dizendo:&lt;br&gt;
&lt;strong&gt;“Estou aqui. Estou pronto para aprender. Bora criar.”&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Reflexão para iniciantes&lt;/h2&gt;
&lt;p&gt;Se você está começando agora, entenda que não existe código pequeno demais.&lt;br&gt;
Todo grande projeto começa com algo mínimo, às vezes com duas palavras.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Escreva, rode, erre, aprenda. Repita.&lt;/strong&gt;&lt;br&gt;
O importante é dar o primeiro passo — e ele pode ser um simples &amp;quot;Hello, World!&amp;quot;.&lt;/p&gt;
&lt;h2&gt;Perguntas frequentes sobre Hello World&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;O que significa Hello World na programação?&lt;/strong&gt;
É o programa mais simples possível, usado para testar se o ambiente de desenvolvimento (compilador, terminal, IDE) está funcionando antes de partir para algo mais complexo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;De onde vem o Hello World?&lt;/strong&gt;
A primeira aparição registrada está no livro &lt;em&gt;The C Programming Language&lt;/em&gt; (1978), de Brian Kernighan e Dennis Ritchie.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Por que todo mundo começa por Hello World?&lt;/strong&gt;
Porque dá feedback instantâneo, não exige lógica complexa e mostra que sua máquina está pronta para programar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E depois do Hello World, por onde seguir?&lt;/strong&gt;
Bons próximos passos são adotar boas práticas desde cedo, como &lt;a href=&quot;https://blog.erikfigueiredo.com.br/posts/como-finalmente-comecar-com-tdd-de-forma-nao-forcada/&quot;&gt;TDD&lt;/a&gt;, e estudar padrões de projeto como o &lt;a href=&quot;https://blog.erikfigueiredo.com.br/posts/voce-esta-usando-node-js-errado-descubra-o-poder-do-factory-method-e-mude-sua-vida/&quot;&gt;Factory Method em Node.js&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Nunca subestime o valor de um começo.&lt;br&gt;
&amp;quot;Hello, World!&amp;quot; pode parecer insignificante, mas representa coragem, curiosidade e um mundo de possibilidades.&lt;/p&gt;
&lt;p&gt;Seja qual for sua stack, framework ou editor favorito…&lt;br&gt;
...o mais importante é continuar dizendo &lt;strong&gt;olá&lt;/strong&gt; para novos desafios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Em resumo:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hello World é um ritual técnico que valida o ambiente de desenvolvimento.&lt;/li&gt;
&lt;li&gt;Mais do que código, ele simboliza o primeiro contato real entre dev e máquina.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Hello, futuro dev. Hello, mundo.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;🚀🌍&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Factory Method em Node.js: organize gateways de pagamento</title>
    <link href="https://blog.erikfigueiredo.com.br/posts/voce-esta-usando-node-js-errado-descubra-o-poder-do-factory-method-e-mude-sua-vida/" />
    <updated>2025-05-23T00:00:00Z</updated>
    <id>https://blog.erikfigueiredo.com.br/posts/voce-esta-usando-node-js-errado-descubra-o-poder-do-factory-method-e-mude-sua-vida/</id>
    <content type="html">&lt;div class=&quot;cover-image&quot;&gt;
  &lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blog.erikfigueiredo.com.br/img/qvju8jbE64-1200.webp 1200w&quot;&gt;&lt;img src=&quot;https://blog.erikfigueiredo.com.br/img/qvju8jbE64-1200.jpeg&quot; alt=&quot;Capa do artigo: Factory Method em Node.js — organize gateways de pagamento&quot; width=&quot;1200&quot; height=&quot;800&quot; loading=&quot;lazy&quot;&gt;&lt;/picture&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Factory Method&lt;/strong&gt; é um padrão de projeto criacional que delega para subclasses a decisão de qual objeto instanciar, mantendo o código aberto para extensão e fechado para modificação (Open/Closed Principle). Em Node.js, ele resolve elegantemente o problema de classes que crescem sem controle quando você adiciona novos integradores — como gateways de pagamento.&lt;/p&gt;
&lt;p&gt;Já se sentiu equilibrando vários métodos diferentes na mesma classe Node.js, cada um com sua API e suas peculiaridades? Quando o projeto cresce, essa &amp;quot;classe canivete suíço&amp;quot; vira um problema sério de manutenção.&lt;/p&gt;
&lt;p&gt;Neste artigo eu mostro como o &lt;strong&gt;Factory Method&lt;/strong&gt; resolve esse cenário com um exemplo prático: um sistema de gateways de pagamento (PagSeguro, PayPal, Stripe, Mercado Pago) refatorado passo a passo em TypeScript.&lt;/p&gt;
&lt;h2&gt;A classe problemática&lt;/h2&gt;
&lt;p&gt;Imagine que você tem a classe a seguir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;class Payment {
  async pagSeguro() {
    // Simulação de chamada assíncrona para PagSeguro
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PagSeguro&#39;, status: &#39;success&#39; });
      }, 500); // Simula um atraso de 500ms
    });
  }

  async paypal() {
    // Simulação de chamada assíncrona para PayPal
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PayPal&#39;, status: &#39;pending&#39; });
      }, 300); // Simula um atraso de 300ms
    });
  }

  async stripe() {
    // Simulação de chamada assíncrona para Stripe
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Stripe&#39;, status: &#39;error&#39; });
      }, 700); // Simula um atraso de 700ms
    });
  }

  async mercadoPago() {
    // Simulação de chamada assíncrona para Mercado Pago
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Mercado Pago&#39;, status: &#39;success&#39; });
      }, 400); // Simula um atraso de 400ms
    });
  }
}

// Exemplo de uso
const payment = new Payment();

payment.pagSeguro().then((data) =&amp;gt; console.log(data));
payment.paypal().then((data) =&amp;gt; console.log(data));
payment.stripe().then((data) =&amp;gt; console.log(data));
payment.mercadoPago().then((data) =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Num primeiro momento, pode ser que você não veja problemas na implementação, mas os olhares mais experientes já notaram que a implementação real da classe pode ser um problema.&lt;/p&gt;
&lt;p&gt;Imagine que cada método terá sua própria implementação de conexão com o gateway, com as suas próprias importações de classes, tipos e afins, essa classe facilmente terá algumas centenas, talvez milhares de linhas, aumentando muito cada novo gateway implementado.&lt;/p&gt;
&lt;p&gt;Além desse problema óbvio de responsabilidade única, estamos quebrando o princípio de Open/Closed do SOLID.&lt;/p&gt;
&lt;p&gt;Princípio Open/Closed diz que classes, módulos, funções e outras entidades de &lt;em&gt;software&lt;/em&gt; devem ser abertas para expansão, mas fechadas para modificação.&lt;/p&gt;
&lt;h2&gt;O que é Factory Method&lt;/h2&gt;
&lt;p&gt;Factory method é um padrão de projeto criacional que define uma interface para criar objetos em uma superclasse, mas permitindo que as subclasses definam o objeto a ser criado.&lt;/p&gt;
&lt;p&gt;Em termos não tão técnicos, teremos subclasses que seguem uma &lt;em&gt;interface&lt;/em&gt;, a superclasse instancia a subclasse, que irá executar a sua implementação e retornar o resultado disso.&lt;/p&gt;
&lt;p&gt;Refatorando o exemplo acima para o factory method, teríamos:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// Interface ou classe abstrata para gateways de pagamento
interface PaymentProvider {
  processPayment(): Promise&amp;lt;any&amp;gt;;
}

// Classes concretas para cada gateway de pagamento (as subclasses)
// Note que TODAS DEVEM implementar a interface PaymentProvider
class PagSeguroPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;any&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PagSeguro&#39;, status: &#39;success&#39; });
      }, 500);
    });
  }
}

class PaypalPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;any&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PayPal&#39;, status: &#39;pending&#39; });
      }, 300);
    });
  }
}

class StripePayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;any&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Stripe&#39;, status: &#39;error&#39; });
      }, 700);
    });
  }
}

class MercadoPagoPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;any&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Mercado Pago&#39;, status: &#39;success&#39; });
      }, 400);
    });
  }
}

// Classe Factory Method (a superclasse)
class PaymentFactory {
  createPayment(gateway: string): PaymentProvider {
    switch (gateway) {
      case &#39;pagSeguro&#39;:
        return new PagSeguroPayment();
      case &#39;paypal&#39;:
        return new PaypalPayment();
      case &#39;stripe&#39;:
        return new StripePayment();
      case &#39;mercadoPago&#39;:
        return new MercadoPagoPayment();
      default:
        throw new Error(&#39;Provedor de pagamento inválido.&#39;);
    }
  }
}

// Exemplo de uso
const paymentFactory = new PaymentFactory();

paymentFactory.createPayment(&#39;pagSeguro&#39;).processPayment().then((data) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;paypal&#39;).processPayment().then((data) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;stripe&#39;).processPayment().then((data) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;mercadoPago&#39;).processPayment().then((data) =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Com isso já temos classes diferentes para cada gateway de pagamento e isso já resolve o problema principal, agora cada gateway tem a sua classe e pode ficar num arquivo separado e mais fácil de manter, já que a interface define até o que deve ser retornado.&lt;/p&gt;
&lt;p&gt;Eu ainda melhoria um pouco alterando o tipo do retorno da interface:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;interface PaymentResult {
  provider: string;
  status: &#39;success&#39; | &#39;pending&#39; | &#39;error&#39;;
}

interface PaymentProvider {
  processPayment(): Promise&amp;lt;PaymentResult&amp;gt;;
}

// Classes concretas para cada gateway de pagamento (as subclasses)
// Note que TODAS DEVEM implementar a interface PaymentProvider
class PagSeguroPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;PaymentResult&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PagSeguro&#39;, status: &#39;success&#39; });
      }, 500);
    });
  }
}

class PaypalPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;PaymentResult&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PayPal&#39;, status: &#39;pending&#39; });
      }, 300);
    });
  }
}

class StripePayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;PaymentResult&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Stripe&#39;, status: &#39;error&#39; });
      }, 700);
    });
  }
}

class MercadoPagoPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;any&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Mercado Pago&#39;, status: &#39;success&#39; });
      }, 400);
    });
  }
}

// Classe Factory Method (a superclasse)
class PaymentFactory {
  createPayment(gateway: string): PaymentProvider {
    switch (gateway) {
      case &#39;pagSeguro&#39;:
        return new PagSeguroPayment();
      case &#39;paypal&#39;:
        return new PaypalPayment();
      case &#39;stripe&#39;:
        return new StripePayment();
      case &#39;mercadoPago&#39;:
        return new MercadoPagoPayment();
      default:
        throw new Error(&#39;Provedor de pagamento inválido.&#39;);
    }
  }
}

// Exemplo de uso
const paymentFactory = new PaymentFactory();

paymentFactory.createPayment(&#39;pagSeguro&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;paypal&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;stripe&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;mercadoPago&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E essa injeção de dependências? Não existe?&lt;/p&gt;
&lt;p&gt;Em alguns padrões de projeto vemos este tipo de abordagem em que as classes são instanciadas dentro da superclasse, sem injeção externa da dependência, não há uma resposta única que determine que não injetar as classes seja sempre um &amp;quot;erro&amp;quot;. Ambas as abordagens têm as suas vantagens e desvantagens, vale falar mais sobre isso em outro momento ou nos comentários.&lt;/p&gt;
&lt;p&gt;Mas se você se incomodou, QUE ÓTIMO, sempre dá para melhorar.&lt;/p&gt;
&lt;p&gt;No contexto do factory method, uma injeção de dependências mais atrapalharia do que ajudaria, adicionando uma camada extra de complexidade com a qual não precisamos lidar, mas eu ficaria muito mais confortável se a minha factory seguisse a ideia que já apresentei do Open/Closed Principle, por isso criei um objeto de registro das classes, que eu posso atualizar &amp;quot;de fora&amp;quot; da factory e nunca precisar abrir ela para expandir as suas funcionalidades.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
// Aqui eu registro minhas classes
export const classMap = {
  pagSeguro: PagSeguroPayment,
  paypal: PaypalPayment,
  stripe: StripePayment,
  mercadoPago: MercadoPagoPayment,
}

// Classe Factory Method mais dinâmica
class PaymentFactory {
  createPayment(provider: keyof typeof classMap): PaymentProvider {
	return new classMap[provider]()
  }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora eu posso fazer todo o processo de incluir um novo gateway de pagamento sem alterar qualquer classe existente, pra isso eu preciso:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Criar a classe implementando a &lt;em&gt;interface&lt;/em&gt; PaymentProvider&lt;/li&gt;
&lt;li&gt;Registrar no classMap utilizando o padrão &lt;code&gt;stringParaOParametroProviderDoMetodoCreatePayment&lt;/code&gt;:  MinhaClasse&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Código final:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;interface PaymentResult {
  provider: string;
  status: &#39;success&#39; | &#39;pending&#39; | &#39;error&#39;;
}

interface PaymentProvider {
  processPayment(): Promise&amp;lt;PaymentResult&amp;gt;;
}

// Classes concretas para cada gateway de pagamento (as subclasses)
// Note que TODAS DEVEM implementar a interface PaymentProvider
class PagSeguroPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;PaymentResult&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PagSeguro&#39;, status: &#39;success&#39; });
      }, 500);
    });
  }
}

class PaypalPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;PaymentResult&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;PayPal&#39;, status: &#39;pending&#39; });
      }, 300);
    });
  }
}

class StripePayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;PaymentResult&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Stripe&#39;, status: &#39;error&#39; });
      }, 700);
    });
  }
}

class MercadoPagoPayment implements PaymentProvider {
  async processPayment(): Promise&amp;lt;any&amp;gt; {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        resolve({ provider: &#39;Mercado Pago&#39;, status: &#39;success&#39; });
      }, 400);
    });
  }
}

// Aqui eu registro minhas classes
export const classMap = {
  pagSeguro: PagSeguroPayment,
  paypal: PaypalPayment,
  stripe: StripePayment,
  mercadoPago: MercadoPagoPayment,
}


// Classe Factory Method mais dinâmica
class PaymentFactory {
  createPayment(provider: keyof typeof classMap): PaymentProvider {
	return new classMap[provider]()
  }
}

// Exemplo de uso
const paymentFactory = new PaymentFactory();

paymentFactory.createPayment(&#39;pagSeguro&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;paypal&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;stripe&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
paymentFactory.createPayment(&#39;mercadoPago&#39;).processPayment().then((data: PaymentResult) =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O resultado é tão interessante que você pode manter como exemplo acima (assíncrono) ou rodar de forma síncrona:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;const init = async () =&amp;gt; {
  const paymentFactory = new PaymentFactory();

  let data1 = await paymentFactory.createPayment(&#39;pagSeguro&#39;).processPayment();
  console.log(data1);

  let data2 = await paymentFactory.createPayment(&#39;paypal&#39;).processPayment();
  console.log(data2);

  let data3 = await paymentFactory.createPayment(&#39;stripe&#39;).processPayment();
  console.log(data3);

  let data4 = await paymentFactory.createPayment(&#39;mercadoPago&#39;).processPayment();
  console.log(data4);

}

init();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E os resultados podem ser vistos acompanhando a ordem em que os logs disparam:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;➜  factory-method node_modules/.bin/ts-node teste.ts
{ provider: &#39;PayPal&#39;, status: &#39;pending&#39; }
{ provider: &#39;Mercado Pago&#39;, status: &#39;success&#39; }
{ provider: &#39;PagSeguro&#39;, status: &#39;success&#39; }
{ provider: &#39;Stripe&#39;, status: &#39;error&#39; }
➜  factory-method node_modules/.bin/ts-node teste.ts
{ provider: &#39;PagSeguro&#39;, status: &#39;success&#39; }
{ provider: &#39;PayPal&#39;, status: &#39;pending&#39; }
{ provider: &#39;Stripe&#39;, status: &#39;error&#39; }
{ provider: &#39;Mercado Pago&#39;, status: &#39;success&#39; }
➜  factory-method 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Na primeira execução utilizamos o exemplo assíncrono e o segundo de forma síncrona.&lt;/p&gt;
&lt;p&gt;A diferença é que de forma assíncrona todos são executados ao mesmo tempo, e a ordem de retorno do &lt;em&gt;log&lt;/em&gt; é por &amp;quot;quem é mais rápido&amp;quot;, por isso o PayPal é o primeiro a retornar.&lt;/p&gt;
&lt;p&gt;No resultado síncrono, os métodos são executados um após o outro, aguardando o anterior finalizar antes de seguir para o próximo, por isso a ordem é a de execução, por isso o PagSeguro é o primeiro a retornar.&lt;/p&gt;
&lt;h2&gt;Perguntas frequentes sobre Factory Method em Node.js&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;O que é Factory Method?&lt;/strong&gt;
É um padrão de projeto criacional que define uma interface comum para criar objetos, deixando que subclasses decidam qual classe concreta instanciar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quando usar Factory Method em vez de instanciar a classe diretamente?&lt;/strong&gt;
Quando você tem várias implementações de uma mesma &amp;quot;ideia&amp;quot; (ex: gateways de pagamento, drivers de banco, providers de notificação) e quer adicionar novas sem mexer nas existentes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Factory Method é o mesmo que Abstract Factory?&lt;/strong&gt;
Não. Factory Method cria UM produto por subclasse. Abstract Factory cria FAMÍLIAS de produtos relacionados. Para gateways simples, Factory Method é suficiente.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Por que usar &lt;code&gt;classMap&lt;/code&gt; em vez de &lt;code&gt;switch case&lt;/code&gt;?&lt;/strong&gt;
Porque permite registrar novas implementações sem abrir o código da Factory — respeitando o Open/Closed Principle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Factory Method ajuda na testabilidade?&lt;/strong&gt;
Sim. Como cada implementação fica isolada em sua própria classe, fica muito mais fácil mockar ou testar uma por vez — combina bem com práticas como &lt;a href=&quot;https://blog.erikfigueiredo.com.br/posts/como-finalmente-comecar-com-tdd-de-forma-nao-forcada/&quot;&gt;TDD&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Ainda dá para melhorar mais&lt;/h2&gt;
&lt;p&gt;Sim! Se você aliar o Factory Method a um Proxy, vamos conseguir voltar ao formato de execução inicial, fazendo com que cada subclasse seja utilizada como um método da classe Factory, assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;const payment = new Payment();

payment.pagSeguro().then((data) =&amp;gt; console.log(data));
payment.paypal().then((data) =&amp;gt; console.log(data));
payment.stripe().then((data) =&amp;gt; console.log(data));
payment.mercadoPago().then((data) =&amp;gt; console.log(data));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Na utilização parece ser uma única classe, mas por baixo dos panos estamos chamando as subclasses em vez de métodos, &amp;quot;is magic&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Factory Method centraliza a criação de objetos sob uma interface comum.&lt;/li&gt;
&lt;li&gt;Cada provedor vira uma classe isolada, mais fácil de testar e manter.&lt;/li&gt;
&lt;li&gt;Usar um &lt;code&gt;classMap&lt;/code&gt; no lugar de &lt;code&gt;switch&lt;/code&gt; mantém o Open/Closed Principle vivo.&lt;/li&gt;
&lt;li&gt;Próximo passo: combinar com Proxy para reaproveitar a sintaxe original &lt;code&gt;payment.pagSeguro()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mas isso é só um gostinho do que vamos falar no próximo artigo, dependendo do desempenho deste aqui.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>TDD na prática: como adotar Test Driven Development sem dor</title>
    <link href="https://blog.erikfigueiredo.com.br/posts/como-finalmente-comecar-com-tdd-de-forma-nao-forcada/" />
    <updated>2025-05-23T00:00:00Z</updated>
    <id>https://blog.erikfigueiredo.com.br/posts/como-finalmente-comecar-com-tdd-de-forma-nao-forcada/</id>
    <content type="html">&lt;div class=&quot;cover-image&quot;&gt;
  &lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blog.erikfigueiredo.com.br/img/EKn5uS8j2e-1200.webp 1200w&quot;&gt;&lt;img src=&quot;https://blog.erikfigueiredo.com.br/img/EKn5uS8j2e-1200.jpeg&quot; alt=&quot;Capa do artigo: Como finalmente começar com TDD de forma não forçada&quot; width=&quot;1200&quot; height=&quot;800&quot; loading=&quot;lazy&quot;&gt;&lt;/picture&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Este artigo NÃO É UM TUTORIAL - vou compartilhar as minhas experiências com TDD com a intenção de te mostrar um caminho mais óbvio para trabalhar com testes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sabe por que eu demorei TANTO tempo para usar TDD depois que aprendi? Porque eu sabia o que era e como fazia, mas não sabia pra que servia &amp;quot;de verdade&amp;quot;.&lt;/p&gt;
&lt;p&gt;Estranho, né?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TDD é bom, confia! - Ciano do Among US&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;TDD (Test Driven Development)&lt;/strong&gt; é uma prática de desenvolvimento em que você escreve o teste antes do código de produção, seguindo o ciclo &lt;strong&gt;Red → Green → Refactor&lt;/strong&gt;. Funciona para qualquer linguagem e qualquer tipo de teste automatizado — não só testes unitários.&lt;/p&gt;
&lt;h2&gt;O que é TDD&lt;/h2&gt;
&lt;p&gt;Para nivelarmos a conversa vou explicar o que é TDD, se você já sabe, parabéns e pule este tópico.&lt;/p&gt;
&lt;p&gt;TDD é o acrônimo de Test Driven Development ou, como chamamos aqui em terras tupiniquins, Desenvolvimento Orientado a Testes.&lt;/p&gt;
&lt;p&gt;Na prática, apenas escrevemos o código com base em um teste pré-estabelecido, isso quer dizer que criamos uma classe de teste que &amp;quot;usa&amp;quot; a classe que você está desenvolvendo e tentamos cobrir TODAS as possibilidades enquanto isolamos completamente o que queremos testar para evitar efeitos colaterais*.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;* Para isolar a classe precisamos criar cópias com métodos e retornos controlados das OUTRAS classes que precisamos para a principal funcionar, isso se chama mock.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TDD tem 3 estágios.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Red: O teste é criado e falha, já que o código testado ainda não existe&lt;/li&gt;
&lt;li&gt;Green: O teste passa, normalmente da forma mais simples possível.&lt;/li&gt;
&lt;li&gt;Refactor: Aqui revemos o código e alteramos com possíveis melhorias ou até mesmo para implementar outras features/cenários, este último passo pode se repetir quantas vezes forem necessárias.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Um ponto importante que devemos ressaltar é que TDD é uma prática para teste automatizado e não teste unitário, pode existir TDD sem teste unitário (teste comportamental, por exemplo).&lt;/p&gt;
&lt;h2&gt;Como se faz TDD&lt;/h2&gt;
&lt;p&gt;Para expandir este artigo e evitar ser repetitivo (acho que já fui no tópico anterior), leia este artigo do &lt;a href=&quot;https://dev.to/eduardofg87&quot;&gt;Eduardo Figueiredo&lt;/a&gt; - &amp;quot;nice lastname, Edu&amp;quot;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/phpbrasil/tdd-iniciando-com-tdd-no-php-47nb&quot;&gt;TDD: Iniciando com TDD no PHP&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Pra que serve TDD&lt;/h2&gt;
&lt;p&gt;O tópico principal!!!&lt;/p&gt;
&lt;p&gt;TDD serve para que o desenvolvimento possa ser mantido em um ritmo saudável enquanto garantimos que as features anteriores estão funcionando da forma esperada.&lt;/p&gt;
&lt;p&gt;Pode parecer muito, mas MUITO besta pra você, mas minha mente limitada só conseguiu entender como usar o TDD de forma produtiva quando refletiu sobre o &amp;quot;para que serve o TDD&amp;quot;*.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;* Por isso resolvi escrever este artigo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;O método de desenvolver testando no navegador é MUITO prático e largamente utilizado, mas tem um problema que cresce com o tamanho do projeto (linhas de código). Em algum momento vamos precisar voltar e testar partes do projeto que já &amp;quot;estavam prontos&amp;quot; e isso escala em complexidade e quantidade de testes.&lt;/p&gt;
&lt;p&gt;Uma alteração em um evento ou middleware (se quiser saber mais sobre as &lt;a href=&quot;https://blog.erikfigueiredo.com.br/serie-php-sem-frameworks/&quot;&gt;camadas de um projeto PHP leia este artigo&lt;/a&gt; que escrevi) pode fazer com que várias partes de um projeto sejam afetadas, os testes garantem que estas mesmas partes possam ser testadas novamente e dar um feedback de sucesso ou falha em pouco tempo, de forma automatizada.&lt;/p&gt;
&lt;p&gt;Isso evita que algum lugar que você nem imaginou (ou lembrou) acabe apresentando um bug por conta destas alterações (isso também deixa claro o motivo de testes unitários não serem suficientes).&lt;/p&gt;
&lt;h2&gt;Exemplos práticos&lt;/h2&gt;
&lt;p&gt;Eu tenho dois exemplos em que o TDD ajudou muito em tarefas que seriam complicadas demais.&lt;/p&gt;
&lt;h3&gt;Refatoração ENORME de um projeto &amp;quot;mais enorme&amp;quot; ainda&lt;/h3&gt;
&lt;p&gt;Eu tenho um projeto em andamento desenvolvido em Laravel e modularizado, já estávamos em 21 módulos e mais de 1500 classes escritas e aconteceu de precisarmos reduzir estes módulos para apenas 10 (de 21 para 10).&lt;/p&gt;
&lt;p&gt;Embora esteja tudo MUITO organizado em módulos e excelentes boas práticas, realizar as alterações de namespace e dependências do Composer demandaria MUITO teste da minha parte, o que iria inviabilizar a tarefa e provavelmente esta melhoria NUNCA seria realizada.&lt;/p&gt;
&lt;p&gt;A tarefa foi realizada e entregue em um prazo de menos de 10 dias, contando os testes do QA (que eram manuais), e vale ressaltar que eu não fiz qualquer hora extra.&lt;/p&gt;
&lt;p&gt;A cada módulo que eu refatorava executava um total de 850 testes em aproximadamente 10 minutos, o que garantiu que a tarefa chegasse sem erros na fase de testes.&lt;/p&gt;
&lt;h3&gt;Desenvolvimento de um SDK para Facebook Bot API&lt;/h3&gt;
&lt;p&gt;Esse aqui foi um SDK (um pacote para acessar uma API - &amp;quot;tradução&amp;quot; do termo MUITO resumida) para acessar a API de BOT do Facebook.&lt;/p&gt;
&lt;p&gt;A verdade é que eu não teria uma página servida na internet, pensei em criar um arquivo PHP para executar os testes de desenvolvimento e saber se estava correto, mas descartei essa possibilidade em segundos.&lt;/p&gt;
&lt;p&gt;Instalei o PHPUnit e integrei na IDE*, eu escrevia o teste e a classe e teclava um atalho (F5, eu acho) e os testes eram TODOS executados, não dava pra ser mais prático.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;* Na época eu usava o PHPStorm, mas acho que pode ser feito em qualquer IDE, VSCode eu tenho certeza que rola.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Se eu fosse fazer o mesmo no navegador ia ficar reescrevendo o arquivo PHP e talvez teria que usar &lt;code&gt;ctrl+z&lt;/code&gt; para voltar aos testes anteriores, o que é BEM menos eficiente.&lt;/p&gt;
&lt;p&gt;Eu escrevo um teste para uma situação e ela está pronta, é só partir pra outra.&lt;/p&gt;
&lt;p&gt;Terminei o SDK bem rápido e duas vezes eu encontrei erros que seriam pegos somente no teste final (por outra pessoa - talvez o cliente) e depois precisei fazer uma refatoração na classe que fazia a requisição no Facebook e quebrei outros 8 cenários de teste, eu estava com pressa (o que já é um erro) e provavelmente não teria visto os erros.&lt;/p&gt;
&lt;h2&gt;Perguntas frequentes sobre TDD&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TDD serve só para teste unitário?&lt;/strong&gt;
Não. TDD é uma prática de desenvolvimento orientado por testes automatizados — pode ser usado com testes comportamentais, de integração, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quais são as 3 fases do TDD?&lt;/strong&gt;
Red (escreve teste que falha), Green (escreve o código mínimo para passar) e Refactor (refina código e testes mantendo tudo verde).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vale a pena usar TDD em projetos pequenos?&lt;/strong&gt;
Vale principalmente quando o projeto crescer — o ganho aparece no momento em que uma alteração afeta partes que você já tinha esquecido. Em scripts curtos e descartáveis, o retorno é menor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TDD combina com padrões de projeto?&lt;/strong&gt;
Sim, e muito. Padrões como &lt;a href=&quot;https://blog.erikfigueiredo.com.br/posts/voce-esta-usando-node-js-errado-descubra-o-poder-do-factory-method-e-mude-sua-vida/&quot;&gt;Factory Method em Node.js&lt;/a&gt; ficam ainda mais fáceis de testar quando cada implementação está isolada em uma classe própria.&lt;/p&gt;
&lt;h2&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TDD é menos sobre &amp;quot;fazer teste&amp;quot; e mais sobre &lt;strong&gt;acelerar feedback&lt;/strong&gt; durante o desenvolvimento.&lt;/li&gt;
&lt;li&gt;Ele paga o investimento quando você precisa refatorar partes que estavam estáveis e não quer torcer pra nada quebrar.&lt;/li&gt;
&lt;li&gt;Funciona em qualquer linguagem com suite de teste automatizado.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;E você tem algum caso real em que TDD te salvou? Conta nos comentários.&lt;/p&gt;
</content>
  </entry>
</feed>