<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>boas práticas Archives - Leonardo Nascimento | Engenheiro de Software</title>
	<atom:link href="https://leonardonascimento.dev/tag/boas-praticas/feed/" rel="self" type="application/rss+xml" />
	<link>https://leonardonascimento.dev/tag/boas-praticas/</link>
	<description>Especializado em backend, APIs e sistemas escaláveis. Experiência em arquitetura de sistemas, integrações, mensageria, performance e aplicações de alta disponibilidade.</description>
	<lastBuildDate>Fri, 23 Jan 2026 21:17:07 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://leonardonascimento.dev/wp-content/uploads/2021/05/cropped-programming-32x32.png</url>
	<title>boas práticas Archives - Leonardo Nascimento | Engenheiro de Software</title>
	<link>https://leonardonascimento.dev/tag/boas-praticas/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>PHP além do CRUD: como escrever código que não vira problema em produção</title>
		<link>https://leonardonascimento.dev/blog/php-alem-do-crud-como-escrever-codigo-que-nao-vira-problema-em-producao/</link>
					<comments>https://leonardonascimento.dev/blog/php-alem-do-crud-como-escrever-codigo-que-nao-vira-problema-em-producao/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Mon, 26 Jan 2026 11:05:00 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[arquitetura de software]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[código limpo]]></category>
		<category><![CDATA[dto]]></category>
		<category><![CDATA[engenharia de software]]></category>
		<category><![CDATA[php avançado]]></category>
		<category><![CDATA[services layer]]></category>
		<category><![CDATA[sistemas em produção]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2348</guid>

					<description><![CDATA[<p>A maioria dos desenvolvedores PHP sabe fazer CRUD.Isso não te torna pleno. Muito menos sênior. O que diferencia um dev mais experiente não é o que ele sabe fazer, mas o que ele evita fazer. Vou te ensinar aqui um padrão prático, usado em projetos reais, que resolve três problemas clássicos: public function store(Request $request){if [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/php-alem-do-crud-como-escrever-codigo-que-nao-vira-problema-em-producao/">PHP além do CRUD: como escrever código que não vira problema em produção</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>A maioria dos desenvolvedores PHP sabe fazer CRUD.<br>Isso não te torna pleno. Muito menos sênior.</p>



<p>O que diferencia um dev mais experiente não é <em>o que ele sabe fazer</em>, mas <strong>o que ele evita fazer</strong>.</p>



<p>Vou te ensinar aqui <strong>um padrão prático</strong>, usado em projetos reais, que resolve três problemas clássicos:</p>



<ul class="wp-block-list">
<li>Controllers inchados</li>



<li>Regras de negócio espalhadas</li>



<li>Código impossível de testar ou evoluir</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>public function store(Request $request)<br>{<br>if (!$request-&gt;email) {<br>return response()-&gt;json([&#8216;error&#8217; =&gt; &#8216;Email obrigatório&#8217;], 422);<br>}</p>



<pre class="wp-block-code"><code>$user = User::create(&#91;
    'name' =&gt; $request-&gt;name,
    'email' =&gt; $request-&gt;email,
]);

Mail::to($user-&gt;email)-&gt;send(new WelcomeMail($user));

Log::info('Usuário criado', &#91;'id' =&gt; $user-&gt;id]);

return response()-&gt;json($user);</code></pre>



<p>}</p>



<p>Funciona? Funciona.</p>



<p>É bom? Não.</p>



<p>Por quê?</p>



<ul class="wp-block-list">
<li>Controller decide regra de negócio</li>



<li>Controller cria usuário</li>



<li>Controller dispara e-mail</li>



<li>Controller registra log</li>
</ul>



<p>Isso <strong>acopla tudo</strong>.</p>



<h2 class="wp-block-heading" id="h-pensamento-pleno-senior-separar-responsabilidade">Pensamento pleno/sênior: separar responsabilidade</h2>



<p>Controller <strong>não decide regra</strong>.<br>Controller <strong>orquestra</strong>.</p>



<p>Vamos refatorar com um <strong>Service + DTO</strong>, padrão simples e poderoso.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-criando-um-dto-data-transfer-object">Criando um DTO (Data Transfer Object)</h2>



<p>Isso evita Request sendo usado como regra de negócio.</p>



<pre class="wp-block-code"><code>final class CreateUserDTO
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
    ) {}
}
</code></pre>



<p>Simples, explícito e tipado.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-criando-o-service-onde-a-regra-mora"> Criando o Service (onde a regra mora)</h2>



<pre class="wp-block-code"><code>final class CreateUserService
{
    public function execute(CreateUserDTO $dto): User
    {
        if (!filter_var($dto-&gt;email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Email inválido');
        }

        $user = User::create(&#91;
            'name' =&gt; $dto-&gt;name,
            'email' =&gt; $dto-&gt;email,
        ]);

        Mail::to($user-&gt;email)-&gt;send(new WelcomeMail($user));

        Log::info('Usuário criado', &#91;'id' =&gt; $user-&gt;id]);

        return $user;
    }
}
</code></pre>



<p>Agora sim:</p>



<ul class="wp-block-list">
<li>Regra centralizada</li>



<li>Código reutilizável</li>



<li>Fácil de testar</li>



<li>Fácil de evoluir</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-controller-limpo-como-deveria-ser"> Controller limpo (como deveria ser)</h2>



<pre class="wp-block-code"><code>public function store(Request $request, CreateUserService $service)
{
    $dto = new CreateUserDTO(
        name: $request-&gt;name,
        email: $request-&gt;email
    );

    $user = $service-&gt;execute($dto);

    return response()-&gt;json($user);
}
</code></pre>



<p>O controller:</p>



<ul class="wp-block-list">
<li>Recebe request</li>



<li>Constrói DTO</li>



<li>Chama serviço</li>



<li>Retorna resposta</li>
</ul>



<p>Nada além disso.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">O ganho real (que júnior não enxerga)</h2>



<h3 class="wp-block-heading" id="h-testabilidade">Testabilidade</h3>



<p>Agora você testa a regra <strong>sem framework</strong>:</p>



<pre class="wp-block-code"><code>public function test_user_creation()
{
    $service = new CreateUserService();

    $dto = new CreateUserDTO(
        name: 'Leo',
        email: 'leo@email.com'
    );

    $user = $service-&gt;execute($dto);

    $this-&gt;assertEquals('Leo', $user-&gt;name);
}
</code></pre>



<p>Sem Request.<br>Sem Controller.<br>Sem gambiarra.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading" id="h-evolucao-sem-dor"> Evolução sem dor</h3>



<p>Amanhã você precisa:</p>



<ul class="wp-block-list">
<li>Enviar evento para fila</li>



<li>Criar usuário em sistema externo</li>



<li>Validar regra nova</li>
</ul>



<p>Você altera <strong>um lugar só</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Mentalidade sênior (isso vale ouro)</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>&#8221; Código que funciona não é código bom.mCódigo bom é o que aguenta mudança.&#8221; </p>
</blockquote>



<p>Pleno/sênior pensa assim:</p>



<ul class="wp-block-list">
<li>Onde essa regra deve morar?</li>



<li>O que vai mudar daqui 6 meses?</li>



<li>Quem vai dar manutenção nisso?</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Erros clássicos que isso evita</h2>



<ul class="wp-block-list">
<li>Fat models</li>



<li>Controllers gigantes</li>



<li>Services que viram controllers</li>



<li>Regra duplicada</li>



<li>Código impossível de refatorar</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Esse tipo de abordagem <strong>não aparece em tutorial de YouTube</strong>, mas é exatamente o que mantém sistemas vivos em produção.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/php-alem-do-crud-como-escrever-codigo-que-nao-vira-problema-em-producao/">PHP além do CRUD: como escrever código que não vira problema em produção</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/php-alem-do-crud-como-escrever-codigo-que-nao-vira-problema-em-producao/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Na minha máquina funciona. Vamos levar sua máquina para o usuário então</title>
		<link>https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/</link>
					<comments>https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Sat, 10 Jan 2026 21:35:00 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Produção]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[ambiente de produção]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[produção]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2277</guid>

					<description><![CDATA[<p>Todo desenvolvedor já disse ou ouviu essa frase: “Na minha máquina funciona”. Em ambiente local, com poucos dados, sem concorrência real e sem dependências instáveis, quase tudo funciona. O problema é que produção não tem nada a ver com o seu computador. Quando alguém usa “funciona local” como argumento técnico, geralmente está ignorando o contexto [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/">Na minha máquina funciona. Vamos levar sua máquina para o usuário então</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Todo desenvolvedor já disse ou ouviu essa frase: <em>“Na minha máquina funciona”</em>. Em ambiente local, com poucos dados, sem concorrência real e sem dependências instáveis, quase tudo funciona. O problema é que <strong>produção não tem nada a ver com o seu computador</strong>.</p>



<p>Quando alguém usa “funciona local” como argumento técnico, geralmente está ignorando o contexto em que o sistema realmente vai operar. E é exatamente aí que os problemas começam.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Em local, você tem controle total. O banco está limpo, a latência é praticamente zero, não existem requisições concorrentes, não há retries, não há jobs acumulados, não há serviços externos oscilando. Você executa uma ação, olha o resultado e segue em frente. É um ambiente artificialmente perfeito.</p>



<p>Produção é o oposto disso.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>A primeira diferença aparece com <strong>concorrência</strong>. Localmente, você clica uma vez. Em produção, dezenas ou centenas de usuários fazem a mesma ação ao mesmo tempo. Jobs rodam em paralelo. Requests competem por recursos. Código que nunca apresentou problema começa a gerar condição de corrida, duplicidade de execução e dados inconsistentes. Nada disso aparece no teste local simples.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Outra diferença crítica é <strong>latência</strong>. Em local, chamadas HTTP e queries são praticamente instantâneas. Em produção, uma API externa pode demorar segundos para responder, ou responder de forma intermitente. Um banco pode ficar lento sob carga. Um cache pode expirar no pior momento. Código que assume resposta imediata funciona local, mas degrada ou trava em produção.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Existe também a questão do <strong>volume de dados</strong>. Local costuma ter poucos registros. Produção tem milhares ou milhões. Queries que pareciam inofensivas passam a consumir tempo e recursos. Loops simples viram gargalo. Processamentos que eram aceitáveis começam a estourar timeout. O problema não é o código “errado”, é o código <strong>não preparado para escala</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Dependências externas são outro ponto ignorado em ambiente local. Muitas vezes você testa com mock, sandbox ou serviço estável. Em produção, serviços externos falham, ficam lentos ou retornam dados inesperados. Se o sistema não foi desenhado para lidar com isso, o erro externo vira indisponibilidade interna.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Local também não expõe problemas de <strong>observabilidade</strong>. Em produção, quando algo dá errado, você precisa responder rápido: o que aconteceu, quando, com qual dado, em qual fluxo. Código que “funciona local” mas não gera logs úteis transforma qualquer incidente em uma investigação longa e cara.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Outro ponto comum é <strong>configuração e ambiente</strong>. Local costuma ter permissões amplas, cache limpo, variáveis simples. Produção tem múltiplos ambientes, secrets, variáveis diferentes, limites de recurso e regras de segurança. Código que assume configuração fixa funciona local e quebra fora dele.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Existe ainda o fator <strong>tempo</strong>. Local você testa agora. Produção roda por semanas ou meses. Vazamentos de memória, acúmulo de jobs, crescimento de filas e degradação progressiva só aparecem com o tempo. “Funciona local” raramente considera isso.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Nada disso significa que testar local não importa. Significa que <strong>teste local valida comportamento</strong>, não valida operação. Ele é necessário, mas está longe de ser suficiente.</p>



<p>Código pronto para produção é aquele que:</p>



<ul class="wp-block-list">
<li>lida bem com concorrência</li>



<li>assume latência e falha</li>



<li>escala com dados reais</li>



<li>é observável</li>



<li>se comporta de forma previsível sob estresse</li>
</ul>



<p>Sem isso, o “funciona local” vira apenas uma falsa sensação de segurança.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>“Funciona local” não é critério de qualidade. É apenas o primeiro degrau. Produção cobra decisões que local nunca vai cobrar: resiliência, previsibilidade e responsabilidade técnica.</p>



<p>Quando alguém entende isso, muda a forma de escrever código. Quando não entende, continua apagando incêndio e se perguntando por que algo que “funcionava perfeitamente” começou a falhar sem explicação.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/">Na minha máquina funciona. Vamos levar sua máquina para o usuário então</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Boas práticas para estruturar projetos em Laravel de médio e grande porte</title>
		<link>https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/</link>
					<comments>https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Wed, 07 Jan 2026 14:12:16 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Produção]]></category>
		<category><![CDATA[arquitetura]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[código sustentável]]></category>
		<category><![CDATA[escalabilidade]]></category>
		<category><![CDATA[estrutura de projeto]]></category>
		<category><![CDATA[laravel]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2262</guid>

					<description><![CDATA[<p>Quando o projeto Laravel é pequeno, quase qualquer organização funciona. Você cria controllers, models, requests, alguns services, resolve tudo no “app/” e segue. O problema começa quando o sistema cresce: mais módulos, mais regras, integrações, filas, diferentes times mexendo no mesmo lugar… e, de repente, o que era simples vira uma base difícil de evoluir. [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/">Boas práticas para estruturar projetos em Laravel de médio e grande porte</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Quando o projeto <a href="https://leonardonascimento.dev/categoria/laravel/" type="category" id="44">Laravel </a>é pequeno, quase qualquer organização funciona. Você cria controllers, models, requests, alguns services, resolve tudo no “app/” e segue. O problema começa quando o sistema cresce: mais módulos, mais regras, integrações, filas, diferentes times mexendo no mesmo lugar… e, de repente, o que era simples vira uma base difícil de evoluir.</p>



<p>Estruturar um projeto Laravel bem não é sobre “<a href="https://leonardonascimento.dev/categoria/arquitetura/" type="category" id="217">inventar arquitetura</a>”. É sobre reduzir atrito: facilitar manutenção, evitar acoplamento desnecessário e deixar o código previsível para quem chega depois.</p>



<p>A seguir estão práticas que funcionam bem em projetos médios e grandes, especialmente quando já existe operação de produção, roadmap e mudanças frequentes.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Comece pela regra: controller não é lugar de lógica</h2>



<p>Controller deveria orquestrar: receber request, validar, chamar a camada certa e responder. Quando regra de negócio fica no controller, você cria um ponto de acoplamento difícil de testar e difícil de reutilizar. Em projeto grande isso vira padrão ruim rapidamente, porque todo mundo copia o que já existe.</p>



<p>O que funciona melhor é mover lógica para classes dedicadas (services/use cases/actions), e deixar o controller como uma “casca” fina. Você ganha clareza, reaproveitamento e testes mais simples.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Estruture por domínio (feature) quando o sistema crescer</h2>



<p>A estrutura padrão do Laravel (Controllers, Models, Jobs, etc.) é ótima até um certo ponto. Em sistemas grandes, ela tende a espalhar a mesma funcionalidade por várias pastas e o dev precisa “caçar” arquivos para entender um fluxo.</p>



<p>Uma abordagem que escala melhor é organizar por <strong>domínio/feature</strong>. Exemplo: tudo relacionado a “Billing” fica próximo (requests, actions, policies, resources, etc.). Isso reduz a fricção para manter e evoluir partes específicas do sistema.</p>



<p>Você não precisa mudar tudo de uma vez. Dá para começar com um ou dois domínios e ir migrando aos poucos, sem reescrever o projeto inteiro.</p>



<h3 class="wp-block-heading">Estrutura tradicional do Laravel (por tipo)</h3>



<pre class="wp-block-preformatted">app/<br>├── Http/<br>│   ├── Controllers/<br>│   ├── Requests/<br>│   └── Resources/<br>├── Models/<br>├── Jobs/<br>├── Policies/<br>├── Services/</pre>



<p>Problema em projeto grande:<br>para entender <strong>Billing</strong>, você precisa abrir 6 pastas diferentes.</p>



<p>Estrutura por domínio / feature</p>



<p>app/<br>└── Domains/<br>└── Billing/<br>├── Http/<br>│ ├── Controllers/<br>│ ├── Requests/<br>│ └── Resources/<br>├── Actions/<br>├── Jobs/<br>├── Policies/<br>├── Models/<br>└── Services/</p>



<p>Ou até mais simples:</p>



<pre class="wp-block-preformatted">app/<br>└── Billing/<br>    ├── BillingController.php<br>    ├── CreateInvoice.php<br>    ├── Invoice.php<br>    ├── InvoicePolicy.php<br>    ├── SendInvoiceJob.php<br>    └── InvoiceResource.php</pre>



<p>O Laravel não se importa com a pasta, desde que o namespace esteja correto.</p>



<h2 class="wp-block-heading">Por que isso escala melhor?</h2>



<p>Porque quando alguém entra no projeto e precisa mexer em Billing:</p>



<ul class="wp-block-list">
<li>não precisa caçar arquivos espalhados</li>



<li>não quebra coisas de outros domínios</li>



<li>entende o fluxo mais rápido</li>



<li>reduz medo de alterar código</li>
</ul>



<p>Em projeto grande, isso faz <strong>muita diferença</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Requests e validações como primeiro filtro</h2>



<p>Em projeto grande, dado ruim entrando vira bug caro. Centralizar validação em <strong>Form Requests</strong> mantém o controller limpo e torna regras de entrada explícitas.</p>



<p>Além disso, vale padronizar:</p>



<ul class="wp-block-list">
<li>mensagens de erro;</li>



<li>formatos de resposta (principalmente APIs);</li>



<li>validações compartilhadas (traits, rules customizadas).</li>
</ul>



<p>Quando a validação é consistente, o sistema vira mais previsível e o time para de reinventar a roda a cada endpoint.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Padronize respostas de API desde cedo</h2>



<p>Quando cada <a href="https://leonardonascimento.dev/tag/api/" type="post_tag" id="210">endpoint </a>responde de um jeito, cada client precisa de lógica diferente, e isso vira dívida técnica distribuída. Para projetos médios e grandes, uma camada consistente de resposta é obrigatória: Resources, transformers, ou uma padronização interna.</p>



<p>O ponto aqui não é “estética”. É operação. Quando algo quebra, você quer logs previsíveis, payload previsível, erros previsíveis. Isso reduz tempo de diagnóstico.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Regras de negócio: não misture persistência com decisão</h2>



<p>Um erro comum em Laravel é “decidir” coisas dentro de models e ao mesmo tempo persistir em todo lugar, sem fronteira clara. Em sistemas maiores, o ideal é separar:</p>



<ul class="wp-block-list">
<li><strong>Decisão / regra</strong> (o que pode ou não pode)</li>



<li><strong>Persistência</strong> (salvar, consultar)</li>



<li><strong>Orquestração</strong> (fluxo do caso de uso)</li>
</ul>



<p>Isso permite evoluir regra sem quebrar camada de persistência, e vice-versa. E facilita testar o que realmente importa: a regra.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Jobs, filas e idempotência não são detalhe</h2>



<p>Em projeto grande, você inevitavelmente vai para filas: e-mails, notificações, integrações, processamento pesado. O que quebra sistemas grandes não é “usar fila”. É usar fila sem cuidado com:</p>



<ul class="wp-block-list">
<li>idempotência (job rodar duas vezes sem duplicar efeito);</li>



<li>retries (quando deve tentar de novo e quando deve falhar);</li>



<li>timeouts;</li>



<li>dead letter / estratégia para falhas recorrentes;</li>



<li>logs por job.</li>
</ul>



<p>Se o seu projeto depende de integração externa, trate isso como cenário normal: o externo vai falhar. A fila é o lugar certo para absorver isso, desde que bem desenhado.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Serviços externos: isole e trate como dependência instável</h2>



<p>Integrações externas deveriam estar em classes próprias (clients/adapters), com:</p>



<ul class="wp-block-list">
<li>timeout explícito;</li>



<li>tratamento de erro consistente;</li>



<li>retry controlado quando fizer sentido;</li>



<li>logs contextualizados.</li>
</ul>



<p>Evite espalhar <code>Http::post()</code> por todo lugar. Em projeto grande isso vira caos, porque não existe ponto único para ajustar comportamento (ex: mudar header, adicionar auth, alterar timeout).</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Migrations, seeds e dados de referência bem cuidados</h2>



<p>Projeto grande normalmente tem muita migration. E migration desorganizada vira armadilha: ambientes quebram, dev novo não sobe projeto, staging fica inconsistente.</p>



<p>Boas práticas que ajudam:</p>



<ul class="wp-block-list">
<li>migrations com nomes claros;</li>



<li>dados de referência (enums/tabelas fixas) com seeders idempotentes;</li>



<li>evitar “seed que depende de estado manual”;</li>



<li>sempre testar “do zero” em ambiente limpo.</li>
</ul>



<p>Isso evita que o setup do projeto vire uma gincana.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Configuração: tudo em config e .env, nada hardcoded</h2>



<p>Quando cresce, o sistema precisa rodar em múltiplos ambientes e, muitas vezes, múltiplos clientes. Configuração hardcoded vira problema de deploy e vira risco de segurança.</p>



<p>Padronize:</p>



<ul class="wp-block-list">
<li><code>config/*.php</code> como fonte de configuração;</li>



<li><code>.env</code> apenas para valores variáveis;</li>



<li>nunca commitar senhas e keys;</li>



<li>e preferencialmente separar integrações por “config + service container”.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Observabilidade: logs estruturados desde o começo</h2>



<p>Em projetos grandes, o custo de “descobrir o que aconteceu” é alto. Sem logs bons você perde tempo, perde confiança e perde previsibilidade operacional.</p>



<p>O que vale padronizar:</p>



<ul class="wp-block-list">
<li>logs com contexto (tenant, user_id, request_id, correlation_id);</li>



<li>níveis corretos (info, warning, error);</li>



<li>logs de integrações e jobs;</li>



<li>e um formato consistente (para facilitar busca).</li>
</ul>



<p>Isso é o que transforma incidentes em diagnóstico rápido.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Testes: foque no que dá retorno real</h2>



<p>Não dá para testar tudo em projeto grande, e tentar fazê-lo costuma falhar. O que dá mais retorno é:</p>



<ul class="wp-block-list">
<li>testes de regras de negócio (unit/integration);</li>



<li>testes de fluxos críticos;</li>



<li>testes de contratos de API;</li>



<li>e testes de integração com serviços externos (com mocks ou ambientes controlados).</li>
</ul>



<p>Teste não é para “subir porcentagem”. É para reduzir risco onde mais dói.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Conclusão</h2>



<p>Projetos Laravel grandes não quebram porque Laravel é limitado. Eles quebram porque a base cresce sem estrutura, sem padrões e sem fronteiras claras entre responsabilidades.</p>



<p>Se você mantiver controllers finos, separar domínio/feature, isolar integrações, tratar filas com seriedade e padronizar validação/retorno/log, o projeto continua evoluindo sem virar um monstro. E o melhor: o time consegue manter velocidade sem sacrificar estabilidade.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/">Boas práticas para estruturar projetos em Laravel de médio e grande porte</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Erros que já cometi em produção (e o que aprendi com eles)</title>
		<link>https://leonardonascimento.dev/blog/erros-que-ja-cometi-em-producao-e-o-que-aprendi-com-eles/</link>
					<comments>https://leonardonascimento.dev/blog/erros-que-ja-cometi-em-producao-e-o-que-aprendi-com-eles/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 15:41:00 +0000</pubDate>
				<category><![CDATA[Sem categoria]]></category>
		<category><![CDATA[aprendizado técnico]]></category>
		<category><![CDATA[arquitetura de software]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[erros em produção]]></category>
		<category><![CDATA[experiência real]]></category>
		<category><![CDATA[produção]]></category>
		<category><![CDATA[sistemas distribuídos]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2259</guid>

					<description><![CDATA[<p>Produção cobra e cobra caro. E quase sempre ensina do jeito mais desconfortável possível. Ao longo do tempo, com sistemas rodando de verdade, usuários usando, integrações acontecendo e volume crescendo, alguns erros deixam de ser teóricos e passam a ter impacto real. Não são erros de sintaxe ou de framework. São erros de decisão, de [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/erros-que-ja-cometi-em-producao-e-o-que-aprendi-com-eles/">Erros que já cometi em produção (e o que aprendi com eles)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Produção cobra e cobra caro. E quase sempre ensina do jeito mais desconfortável possível.</p>



<p>Ao longo do tempo, com sistemas rodando de verdade, usuários usando, integrações acontecendo e volume crescendo, alguns erros deixam de ser teóricos e passam a ter impacto real. Não são erros de sintaxe ou de framework. São erros de decisão, de suposição e, principalmente, de experiência.</p>



<p>Compartilhar esses erros não é exposição. É maturidade técnica.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Um dos primeiros erros que cometi foi <strong>assumir que o “funciona local” era suficiente</strong>. O sistema atendia aos requisitos, passava nos testes básicos e parecia estável. O problema é que produção adiciona concorrência, latência, falhas externas e volume. Coisas que simplesmente não existem no ambiente local. Aprendi cedo que testar comportamento é diferente de testar contexto.</p>



<p>Outro erro recorrente foi <strong>confiar demais em serviços externos</strong>. APIs de terceiros pareciam estáveis até o dia em que começaram a responder lentamente ou falhar intermitentemente. Sem timeout bem definido, sem fallback e sem isolamento, o problema externo se transformou em indisponibilidade interna. A lição aqui foi clara: dependência externa precisa ser tratada como ponto de falha, não como extensão do seu sistema.</p>



<p>Também já subestimei o impacto da <strong>concorrência</strong>. Processos rodando em paralelo, filas consumidas por múltiplos workers e requisições simultâneas expuseram condições de corrida que nunca apareceram em teste. Duplicidade de execução, dados inconsistentes e comportamentos estranhos surgiram sem aviso. Foi aí que aprendi, na prática, que idempotência não é detalhe, é requisito.</p>



<p>Houve momentos em que <strong>cache foi usado como solução rápida</strong>, sem critério. Funcionou no início, melhorou performance, mas criou uma nova classe de problema: inconsistência. Dados desatualizados começaram a aparecer e o esforço para entender se o problema estava no código, no banco ou no cache aumentou bastante. Cache resolveu o sintoma, mas atrasou o diagnóstico da causa real.</p>



<p>Outro erro comum foi <strong>logar pouco ou logar demais</strong>. Logs insuficientes tornam qualquer incidente uma investigação no escuro. Logs excessivos, por outro lado, dificultam encontrar o que realmente importa. Com o tempo, aprendi que log bom é aquele que ajuda a responder perguntas, não o que registra tudo.</p>



<p>Já deixei passar também a importância de <strong>monitorar comportamento, não só infraestrutura</strong>. CPU e memória estavam normais, mas usuários reclamavam de lentidão. O problema não era recurso, era fluxo. A partir daí, ficou claro que disponibilidade e latência percebida dizem muito mais sobre a saúde do sistema do que gráficos isolados.</p>



<p>Em alguns momentos, tomei decisões de arquitetura rígidas cedo demais. Abstrações complexas criadas “pensando no futuro” acabaram dificultando mudanças simples. Arquitetura precisa dar suporte à evolução, não impedir. Esse tipo de erro não quebra o sistema imediatamente, mas cobra juros altos com o tempo.</p>



<p>Por fim, talvez o erro mais sutil tenha sido <strong>não tratar operação como parte do desenvolvimento</strong>. Código foi escrito pensando em funcionalidade, não em manutenção, observabilidade ou resposta a incidentes. Produção mostrou que escrever código é apenas uma parte do trabalho. Operar o sistema é a outra metade.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">O que ficou de aprendizado</h2>



<p>Produção não perdoa suposições. Ela expõe decisões frágeis, atalhos técnicos e falta de preparo. Cada erro deixou uma lição clara: sistemas precisam ser pensados para falhar, para escalar e para serem operados por pessoas reais.</p>



<p>Errar faz parte. Repetir os mesmos erros é escolha.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/erros-que-ja-cometi-em-producao-e-o-que-aprendi-com-eles/">Erros que já cometi em produção (e o que aprendi com eles)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/erros-que-ja-cometi-em-producao-e-o-que-aprendi-com-eles/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Pensar arquitetura antes de escrever código ou sair escrevendo e depois ver no que da?</title>
		<link>https://leonardonascimento.dev/blog/pensar-arquitetura-antes-de-escrever-codigo-ou-sair-escrevendo-e-depois-ver-no-que-da/</link>
					<comments>https://leonardonascimento.dev/blog/pensar-arquitetura-antes-de-escrever-codigo-ou-sair-escrevendo-e-depois-ver-no-que-da/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Sun, 04 Jan 2026 17:56:00 +0000</pubDate>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[arquitetura de software]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[manutenibilidade]]></category>
		<category><![CDATA[produção]]></category>
		<category><![CDATA[qualidade de código]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2254</guid>

					<description><![CDATA[<p>É muito comum começar um sistema abrindo o editor e escrevendo código. Cria um controller, faz uma query, retorna uma resposta e segue o jogo. No começo funciona. E exatamente por isso muita gente continua fazendo assim. O problema é que essa forma de trabalhar escala muito mal. Quando o sistema cresce, quando entra mais [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/pensar-arquitetura-antes-de-escrever-codigo-ou-sair-escrevendo-e-depois-ver-no-que-da/">Pensar arquitetura antes de escrever código ou sair escrevendo e depois ver no que da?</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>É muito comum começar um sistema abrindo o editor e escrevendo código. Cria um controller, faz uma query, retorna uma resposta e segue o jogo. No começo funciona. E exatamente por isso muita gente continua fazendo assim.</p>



<p>O problema é que essa forma de trabalhar escala muito mal.</p>



<p>Quando o sistema cresce, quando entra mais gente no time ou quando surgem novas regras, aquele código que “resolvia” começa a virar um emaranhado difícil de mexer. E aí surge a sensação de que qualquer mudança simples dá trabalho demais.</p>



<p>Isso quase nunca é culpa do código em si. Normalmente é arquitetura que nunca foi pensada.</p>



<p>Código muda o tempo todo. Arquitetura não.</p>



<p>Funções são reescritas, métodos são refatorados, nomes são ajustados. Mas a forma como o sistema foi estruturado lá no começo costuma durar anos. Se a base foi mal pensada, você passa muito tempo brigando com decisões antigas.</p>



<p>É por isso que arquitetura não é detalhe. Ela define o quanto o sistema vai te ajudar ou te atrapalhar no futuro.</p>



<p>Outro erro comum é começar pensando em ferramenta.</p>



<p>“Como faço isso no Laravel?”<br>“Qual padrão eu uso aqui?”<br>“Isso vira um service ou um job?”</p>



<p>Essas perguntas vêm cedo demais.</p>



<p>Antes disso, o que realmente importa é entender o problema. O fluxo. O que entra, o que sai, o que pode falhar, o que precisa ser consistente. Quando isso não está claro, qualquer código escrito vira tentativa e erro.</p>



<p>Framework ajuda, mas não pensa por você.</p>



<p>Misturar responsabilidade quase sempre parece produtivo no início.</p>



<p>Coloca regra no controller, resolve ali mesmo, já retorna a resposta e pronto. Funciona rápido. Até o dia em que você precisa reutilizar aquela lógica, testar isoladamente ou mudar um comportamento sem quebrar outro.</p>



<p>Quando tudo está no mesmo lugar, nada está realmente isolado.</p>



<p>Separar responsabilidade não é academicismo. É o que evita que uma mudança pequena vire um risco desnecessário.</p>



<p>Uma coisa que ajuda muito é pensar no fluxo antes de pensar em classes.</p>



<p>De onde vem o dado?<br>O que valida?<br>Onde a regra acontece?<br>O que persiste?<br>O que retorna?</p>



<p>Quando esse caminho está claro na cabeça, o código flui. Quando não está, você sente que está “programando no escuro”.</p>



<p>Arquitetura ruim costuma esconder dependências.</p>



<p>Você só descobre que uma parte do sistema depende de outra quando tenta mexer em algo e tudo quebra. Isso acontece porque essas dependências nunca foram assumidas, só foram surgindo.</p>



<p>Dependência explícita dói menos do que dependência escondida.</p>



<p>Produção exige previsibilidade.</p>



<p>Não é só sobre funcionar agora, é sobre saber o impacto de uma mudança. Quando a arquitetura é confusa, qualquer ajuste vira medo. Quando é clara, você sabe exatamente onde mexer e o que pode ser afetado.</p>



<p>Esse tipo de tranquilidade não vem do código bonito. Vem de decisões bem pensadas.</p>



<p>Também vale um cuidado importante: decisões irreversíveis cedo demais</p>



<p>Criar abstrações complexas, padrões genéricos ou estruturas “pensando no futuro” costuma travar o sistema antes mesmo dele crescer. Boa arquitetura é flexível. Ela resolve o problema atual sem impedir evolução.</p>



<p>Complexidade prematura cobra juros.</p>



<p>Pensar arquitetura não significa desenhar diagramas enormes nem usar nomes sofisticados. Na maioria das vezes, boa arquitetura é simples o suficiente para ser explicada em poucos minutos.</p>



<p>Se você não consegue explicar como o sistema funciona, provavelmente ele já está mais complexo do que deveria.</p>



<p>No começo, pensar arquitetura parece atrasar. Depois de alguns meses, ela economiza tempo. Menos retrabalho, menos bug colateral, menos receio de mexer no código.</p>



<p>O ganho não é imediato, mas é consistente.</p>



<p><strong>Conclusão</strong></p>



<p>Pensar arquitetura antes de escrever código não é tentar prever tudo. É reduzir incerteza.</p>



<p>É entender o problema antes de sair codando. É isso que separa sistemas que evoluem com tranquilidade daqueles que vão acumulando problemas silenciosos até virar dívida difícil de pagar.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/pensar-arquitetura-antes-de-escrever-codigo-ou-sair-escrevendo-e-depois-ver-no-que-da/">Pensar arquitetura antes de escrever código ou sair escrevendo e depois ver no que da?</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/pensar-arquitetura-antes-de-escrever-codigo-ou-sair-escrevendo-e-depois-ver-no-que-da/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Quando usar cache (e quando ele só complica o sistema)</title>
		<link>https://leonardonascimento.dev/blog/quando-usar-cache-e-quando-ele-so-complica-o-sistema/</link>
					<comments>https://leonardonascimento.dev/blog/quando-usar-cache-e-quando-ele-so-complica-o-sistema/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Sat, 03 Jan 2026 16:47:00 +0000</pubDate>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[arquitetura de software]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[performance]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2251</guid>

					<description><![CDATA[<p>Cache costuma entrar na conversa sempre que alguém fala em performance. A ideia é simples: “se está lento, coloca cache”. O problema é que, na prática, cache mal aplicado resolve um problema e cria outros. Não é raro ver sistemas que até funcionam bem sem cache, mas ficam difíceis de manter depois que ele entra [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/quando-usar-cache-e-quando-ele-so-complica-o-sistema/">Quando usar cache (e quando ele só complica o sistema)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Cache costuma entrar na conversa sempre que alguém fala em performance. A ideia é simples: “se está lento, coloca cache”. O problema é que, na prática, cache mal aplicado resolve um problema e cria outros.</p>



<p>Não é raro ver sistemas que até funcionam bem sem cache, mas ficam difíceis de manter depois que ele entra sem critério.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Cache não é ponto de partida</h2>



<p>Antes de pensar em cache, vale responder uma pergunta básica:<br><strong>onde o sistema está lento?</strong></p>



<p>Muitas vezes o problema não é falta de cache, mas:</p>



<ul class="wp-block-list">
<li>query mal escrita;</li>



<li>lógica duplicada;</li>



<li>processamento desnecessário;</li>



<li>excesso de chamadas externas.</li>
</ul>



<p>Colocar cache sem entender o gargalo real só esconde o problema por um tempo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Quando cache realmente faz sentido</h2>



<p>Cache funciona bem quando você tem:</p>



<ul class="wp-block-list">
<li>dados lidos muitas vezes;</li>



<li>dados que mudam pouco;</li>



<li>custo alto de processamento ou consulta.</li>
</ul>



<p>Configurações, listas estáticas, resultados agregados e respostas de APIs externas são bons candidatos. Nesse cenário, o cache reduz carga e melhora tempo de resposta de forma consistente.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">O problema começa na invalidação</h2>



<p>Cache quase nunca dá problema na criação. Ele dá problema na invalidação.</p>



<p>Quando não fica claro:</p>



<ul class="wp-block-list">
<li>quando o cache expira;</li>



<li>quem invalida;</li>



<li>o que acontece se falhar;</li>
</ul>



<p>o sistema começa a servir dado errado. E dado errado em produção costuma ser pior que erro explícito.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Cache que vira dependência</h2>



<p>Um sinal claro de problema é quando o sistema <strong>depende</strong> do cache para funcionar corretamente.</p>



<p>Se desligar o cache quebra tudo, isso indica que:</p>



<ul class="wp-block-list">
<li>a lógica base não está saudável;</li>



<li>o cache está mascarando problemas estruturais;</li>



<li>o código ficou acoplado demais a essa camada.</li>
</ul>



<p>Cache deveria acelerar, não sustentar o sistema.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Cuidado com cache em dados muito voláteis</h2>



<p>Cache em dados que mudam o tempo todo geralmente gera:</p>



<ul class="wp-block-list">
<li>inconsistência;</li>



<li>comportamento estranho;</li>



<li>bugs intermitentes.</li>
</ul>



<p>Quanto mais volátil o dado, maior o custo mental e técnico para manter o cache correto. Em muitos casos, o ganho de performance não compensa a complexidade introduzida.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Cache também tem custo</h2>



<p>Cache não é gratuito.</p>



<p>Ele consome memória, adiciona mais uma camada ao sistema e aumenta a complexidade de debug. Quando algo dá errado, você precisa verificar:</p>



<ul class="wp-block-list">
<li>código;</li>



<li>banco;</li>



<li>cache;</li>



<li>estratégia de expiração.</li>
</ul>



<p>Cada camada extra aumenta o esforço para entender o que está acontecendo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Uma regra simples que ajuda</h2>



<p>Uma regra prática que costuma funcionar bem:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Primeiro, faça o sistema funcionar corretamente sem cache.<br>Depois, use cache para otimizar pontos específicos e bem entendidos.</p>
</blockquote>



<p>Isso evita decisões precipitadas e mantém o sistema mais previsível.</p>



<h2 class="wp-block-heading">Bancos de cache, CDN e cache em borda: onde cada um faz sentido</h2>



<p>Quando se fala em cache, muita gente mistura tudo como se fosse a mesma coisa. Na prática, existem <strong>camadas diferentes de cache</strong>, cada uma com um papel específico. Entender isso evita decisões erradas e expectativas irreais.</p>



<h2 class="wp-block-heading">Cache em memória (Redis, Memcached)</h2>



<p>Bancos de cache em memória, como Redis, são muito usados no backend porque são rápidos e flexíveis. Eles fazem sentido quando você precisa:</p>



<ul class="wp-block-list">
<li>reduzir acesso ao banco de dados;</li>



<li>compartilhar cache entre múltiplos processos;</li>



<li>armazenar dados temporários com expiração controlada;</li>



<li>lidar com alta concorrência.</li>
</ul>



<p>Redis funciona muito bem para:</p>



<ul class="wp-block-list">
<li>resultados de queries pesadas;</li>



<li>locks e controle de concorrência;</li>



<li>sessões;</li>



<li>dados derivados de outras fontes.</li>
</ul>



<p>O erro comum aqui é transformar o Redis em “banco principal”. Cache não é fonte de verdade. Se os dados do Redis forem perdidos, o sistema precisa continuar funcionando.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Cache de aplicação ≠ cache de infraestrutura</h2>



<p>Cache dentro da aplicação resolve problemas diferentes de cache na borda.</p>



<p>Cache de aplicação (Redis, cache local, etc):</p>



<ul class="wp-block-list">
<li>reduz custo de processamento;</li>



<li>protege banco e serviços internos;</li>



<li>atua no backend.</li>
</ul>



<p>Já cache de infraestrutura atua <strong>antes</strong> da requisição chegar no servidor.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">CDN e cache em borda</h2>



<p>CDN (Content Delivery Network) e cache em borda são ideais para:</p>



<ul class="wp-block-list">
<li>conteúdo estático;</li>



<li>respostas públicas;</li>



<li>páginas que não mudam com frequência.</li>
</ul>



<p>Nesse cenário, o cache:</p>



<ul class="wp-block-list">
<li>reduz latência;</li>



<li>diminui carga no servidor;</li>



<li>melhora experiência do usuário.</li>
</ul>



<p>Cloudflare, por exemplo, atua nesse nível, servindo conteúdo direto da borda sem que a requisição chegue no backend.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Cloudflare não substitui cache de backend</h2>



<p>Um erro comum é achar que, usando Cloudflare ou outra CDN, não é mais necessário cache no backend. Isso não é verdade.</p>



<p>Cloudflare:</p>



<ul class="wp-block-list">
<li>ajuda muito com páginas públicas;</li>



<li>protege contra picos de acesso;</li>



<li>reduz tráfego direto no servidor.</li>
</ul>



<p>Mas ele não resolve:</p>



<ul class="wp-block-list">
<li>lógica pesada no backend;</li>



<li>chamadas internas;</li>



<li>processamento de regras de negócio;</li>



<li>APIs autenticadas.</li>
</ul>



<p>As camadas se complementam, não se substituem.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Combinar camadas de cache com consciência</h2>



<p>Em sistemas mais maduros, é comum ter:</p>



<ul class="wp-block-list">
<li>cache em Redis no backend;</li>



<li>cache HTTP para respostas públicas;</li>



<li>CDN para conteúdo estático;</li>



<li>regras claras de expiração e invalidação.</li>
</ul>



<p>O ponto crítico é não perder controle. Quanto mais camadas, maior a necessidade de saber:</p>



<ul class="wp-block-list">
<li>onde o dado está sendo cacheado;</li>



<li>por quanto tempo;</li>



<li>quem invalida.</li>
</ul>



<p>Sem isso, debug vira loteria.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Cache certo no lugar certo</h2>



<p>Não existe “o melhor cache”. Existe cache adequado ao problema.</p>



<p>Usar Redis para tudo, Cloudflare para tudo ou cachear tudo geralmente leva a soluções frágeis. Cada camada resolve um tipo de problema específico, e ignorar isso gera sistemas difíceis de operar.</p>



<h2 class="wp-block-heading">Um exemplo prático de cache bem aplicado em alto volume</h2>



<p>Em um projeto onde trabalhei, o sistema recebia mais de <strong>30 milhões de visualizações por mês</strong>. O volume era alto, os picos eram imprevisíveis e qualquer erro de arquitetura aparecia rápido.</p>



<p>A solução não foi um único tipo de cache, mas a <strong>combinação correta de camadas</strong>, cada uma resolvendo um problema específico.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Cache no backend</h3>



<p>No backend, utilizávamos cache em memória para reduzir acesso ao banco e evitar processamento repetido. Consultas mais pesadas e dados derivados eram armazenados com tempo de vida bem definido.</p>



<p>Esse cache não era tratado como fonte de verdade. Se fosse limpo ou reiniciado, o sistema continuava funcionando normalmente, apenas com impacto temporário de performance.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Cache no servidor web</h3>



<p>No nível do servidor web, respostas públicas eram cacheadas diretamente, evitando que requisições idênticas chegassem até a aplicação.</p>



<p>Isso reduzia drasticamente:</p>



<ul class="wp-block-list">
<li>consumo de CPU;</li>



<li>execução de código desnecessário;</li>



<li>abertura de conexões com o backend.</li>
</ul>



<p>Para grande parte do tráfego, a aplicação nem chegava a ser executada.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Cache em servidor de borda</h3>



<p>Além disso, havia cache em servidores distribuídos geograficamente, entregando conteúdo diretamente próximo ao usuário final.</p>



<p>Essa camada absorvia picos de acesso e reduzia latência, principalmente em horários de maior tráfego. Em muitos casos, a requisição nem chegava ao servidor de origem.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">O ponto mais importante: controle</h3>



<p>O que fez essa estratégia funcionar não foi o volume de cache, mas o <strong>controle sobre ele</strong>.</p>



<p>Cada camada tinha:</p>



<ul class="wp-block-list">
<li>regras claras de expiração;</li>



<li>critérios bem definidos de cache e bypass;</li>



<li>invalidação consciente quando o conteúdo mudava.</li>
</ul>



<p>Nada era “cacheado por padrão”.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">O resultado prático</h3>



<p>Com essa abordagem:</p>



<ul class="wp-block-list">
<li>o sistema se manteve estável mesmo em picos;</li>



<li>o backend ficou protegido;</li>



<li>o banco deixou de ser gargalo;</li>



<li>a operação ficou previsível.</li>
</ul>



<p>Cache não foi usado como remendo, mas como parte da arquitetura.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Lição aprendida</h3>



<p>Cache funciona quando é pensado como <strong>estratégia</strong>, não como solução emergencial. Em sistemas de alto volume, separar responsabilidades entre backend, servidor web e borda faz toda a diferença.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Conclusão</h2>



<p>Cache é uma ferramenta poderosa, mas perigosa quando usada sem critério. Ele melhora performance quando aplicado com consciência, e cria problemas quando entra apenas como “solução rápida”.</p>



<p>Entender quando <strong>não usar cache</strong> é tão importante quanto saber usá-lo.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/quando-usar-cache-e-quando-ele-so-complica-o-sistema/">Quando usar cache (e quando ele só complica o sistema)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/quando-usar-cache-e-quando-ele-so-complica-o-sistema/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Código em produção: você tem certeza de que ele está pronto?</title>
		<link>https://leonardonascimento.dev/blog/codigo-em-producao-voce-tem-certeza-de-que-ele-esta-pronto/</link>
					<comments>https://leonardonascimento.dev/blog/codigo-em-producao-voce-tem-certeza-de-que-ele-esta-pronto/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Thu, 01 Jan 2026 15:45:00 +0000</pubDate>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[arquitetura de software]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[manutenibilidade]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[produção]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2245</guid>

					<description><![CDATA[<p>Na minha máquina funciona, isso é o suficiente? Muita gente confunde código que simplesmente funciona com código que está realmente pronto para rodar em produção. A diferença entre um e outro costuma aparecer no pior momento possível: em pico de acesso, durante uma campanha, com cliente reclamando ou com o sistema fora do ar. Funcionar [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/codigo-em-producao-voce-tem-certeza-de-que-ele-esta-pronto/">Código em produção: você tem certeza de que ele está pronto?</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Na minha máquina funciona, isso é o suficiente?</p>



<p>Muita gente confunde código que simplesmente funciona com código que está realmente pronto para rodar em produção. A diferença entre um e outro costuma aparecer no pior momento possível: em pico de acesso, durante uma campanha, com cliente reclamando ou com o sistema fora do ar.</p>



<p>Funcionar significa que o código faz o que foi pedido.<br>Código pronto para produção significa que ele continua funcionando <strong>quando tudo começa a dar errado</strong>.</p>



<p>Na prática, código pronto para produção:</p>



<ul class="wp-block-list">
<li>lida com erros de forma previsível;</li>



<li>escala quando a carga aumenta;</li>



<li>se comporta bem sob concorrência;</li>



<li>é observável;</li>



<li>pode ser mantido sem medo;</li>



<li>não depende de sorte.</li>
</ul>



<p></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1) Tratamento de erros</h2>



<p>Produção é um ambiente imprevisível. APIs externas caem. Banco fica lento. Cache expira. Timeouts acontecem.</p>



<p>Se o seu código assume que tudo sempre vai responder corretamente, ele vai quebrar — e rápido.</p>



<p>Código de produção:</p>



<ul class="wp-block-list">
<li>trata exceções;</li>



<li>captura falhas externas;</li>



<li>retorna erros claros;</li>



<li>evita estados quebrados.</li>
</ul>



<p>Ignorar erros não faz eles desaparecerem. Só faz você descobri-los tarde demais.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2) Concorrência</h2>



<p>Concorrência é real. E não é opcional.</p>



<p>Vários usuários, múltiplos processos, jobs rodando ao mesmo tempo, filas sendo consumidas em paralelo. Se o sistema não foi pensado para isso, os problemas aparecem como:</p>



<ul class="wp-block-list">
<li>condições de corrida;</li>



<li>duplicidade de processamento;</li>



<li>registros inconsistentes;</li>



<li>dados sobrescritos.</li>
</ul>



<p>Código que funciona com um usuário não necessariamente funciona com cem.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3) Idempotência</h2>



<p>Esse ponto é ignorado por muita gente.</p>



<p>Em produção, requisições podem ser reenviadas, jobs podem ser reprocessados, webhooks podem disparar mais de uma vez. Se sua lógica não for idempotente, você terá:</p>



<ul class="wp-block-list">
<li>registros duplicados;</li>



<li>ações executadas mais de uma vez;</li>



<li>efeitos colaterais difíceis de desfazer.</li>
</ul>



<p>Código de produção precisa assumir que <strong>a mesma ação pode chegar mais de uma vez</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4) Observabilidade</h2>



<p>Sem logs estruturados, métricas e alertas, você não tem controle — só reação.</p>



<p>Quando algo quebra e você depende de usuário reclamando para descobrir, o problema já escalou.</p>



<p>Código pronto para produção:</p>



<ul class="wp-block-list">
<li>registra eventos relevantes;</li>



<li>gera logs que ajudam a investigar;</li>



<li>permite entender o que aconteceu sem “chutar”.</li>
</ul>



<p>Debug em produção não pode ser baseado em achismo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5) Performance previsível</h2>



<p>Performance não é só velocidade. É previsibilidade.</p>



<p>Um endpoint que responde em 50ms hoje e em 5s amanhã é um problema, mesmo que “funcione”.</p>



<p>Código de produção:</p>



<ul class="wp-block-list">
<li>evita queries desnecessárias;</li>



<li>não faz processamento pesado sem controle;</li>



<li>considera impacto de volume e concorrência.</li>
</ul>



<p>O objetivo não é ser rápido no melhor cenário, mas <strong>estável no pior</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">6) Isolamento de responsabilidades</h2>



<p>Misturar regra de negócio, acesso a dados e controle de requisição cria código frágil.</p>



<p>Quando tudo está acoplado:</p>



<ul class="wp-block-list">
<li>mudanças pequenas viram grandes refatorações;</li>



<li>bugs aparecem em lugares inesperados;</li>



<li>testes se tornam difíceis ou impossíveis.</li>
</ul>



<p>Código de produção separa responsabilidades para reduzir impacto de mudanças.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7) Dependências externas sob controle</h2>



<p>Qualquer integração externa é um ponto de falha.</p>



<p>APIs de terceiros, serviços de pagamento, mensageria, armazenamento. Tudo isso pode falhar.</p>



<p>Código pronto para produção:</p>



<ul class="wp-block-list">
<li>define timeouts;</li>



<li>controla retries;</li>



<li>trata respostas inesperadas;</li>



<li>evita travar o sistema por dependência externa.</li>
</ul>



<p>Assumir que serviços externos “sempre funcionam” é ingenuidade.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">8) Configuração e ambiente</h2>



<p>Código de produção não depende de configuração hardcoded.</p>



<p>Ambientes mudam: local, staging, produção, múltiplos servidores, múltiplos clientes. Se o código não respeita isso, o deploy vira um risco.</p>



<p>Separar configuração de código não é frescura. É requisito básico.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">9) Manutenibilidade</h2>



<p>Se depois de um mês você não entende o que escreveu, o problema não é memória — é o código.</p>



<p>Produção é manutenção contínua. Código precisa ser:</p>



<ul class="wp-block-list">
<li>legível;</li>



<li>previsível;</li>



<li>organizado.</li>
</ul>



<p>Código bom não é o mais curto nem o mais “esperto”. É o que dá menos medo de mexer.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">10) Pensar no impacto futuro</h2>



<p>Código que funciona resolve o agora.<br>Código pronto para produção considera o depois.</p>



<p>Depois de:</p>



<ul class="wp-block-list">
<li>novos usuários;</li>



<li>novas regras;</li>



<li>novas integrações;</li>



<li>novos desenvolvedores no time.</li>
</ul>



<p>Decisões técnicas ruins não quebram tudo na hora — elas cobram juros com o tempo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Conclusão</h2>



<p>Código pronto para produção não é sobre escrever mais código, usar mais ferramentas ou aplicar padrões complexos.</p>



<p>É sobre responsabilidade técnica.</p>



<p>É pensar no que pode dar errado, assumir que vai dar, e preparar o sistema para continuar funcionando mesmo assim. Essa é a diferença real entre sistemas estáveis e sistemas problemáticos.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/codigo-em-producao-voce-tem-certeza-de-que-ele-esta-pronto/">Código em produção: você tem certeza de que ele está pronto?</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/codigo-em-producao-voce-tem-certeza-de-que-ele-esta-pronto/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
