<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Marcelo M. Gonçalves on Medium]]></title>
        <description><![CDATA[Stories by Marcelo M. Gonçalves on Medium]]></description>
        <link>https://medium.com/@marcelomg21?source=rss-56cdc11c288------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*mzGeBgWtFzy8ojidu32p0g.png</url>
            <title>Stories by Marcelo M. Gonçalves on Medium</title>
            <link>https://medium.com/@marcelomg21?source=rss-56cdc11c288------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 14:52:35 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@marcelomg21/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Confiabilidade e Tolerância a falhas: Idempotência, isolamento e recuperação como decisões…]]></title>
            <link>https://medium.com/@marcelomg21/confiabilidade-e-toler%C3%A2ncia-a-falhas-idempot%C3%AAncia-isolamento-e-recupera%C3%A7%C3%A3o-como-decis%C3%B5es-216c3ed568ea?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/216c3ed568ea</guid>
            <category><![CDATA[reliability]]></category>
            <category><![CDATA[quality-attributes]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Fri, 13 Nov 2026 00:23:38 GMT</pubDate>
            <atom:updated>2026-11-13T00:26:26.742Z</atom:updated>
            <content:encoded><![CDATA[<h3>Confiabilidade e Tolerância a falhas: Idempotência, isolamento e recuperação como decisões arquiteturais em sistemas distribuídos</h3><p>Em sistemas distribuídos, falhas não são uma exceção que pode ser simplesmente eliminada. Uma dependência pode ficar indisponível, uma resposta pode se perder no caminho, uma mensagem pode ser entregue mais de uma vez e uma operação pode terminar no destino sem que a origem consiga confirmar o resultado. A arquitetura precisa considerar esses cenários como parte normal do funcionamento do sistema.</p><p>Por isso, confiabilidade não deve ser tratada apenas como disponibilidade ou como a capacidade de manter serviços no ar. Ela envolve preservar o comportamento esperado diante de falhas, limitar seus efeitos, recuperar estados consistentes e evitar que uma ocorrência localizada se transforme em um problema sistêmico. Essa perspectiva desloca a discussão de tecnologias isoladas para decisões arquiteturais orientadas a riscos e requisitos.</p><h3>Confiabilidade como atributo de qualidade</h3><p>Confiabilidade (reliability) representa a capacidade de um sistema executar suas funções sob condições estabelecidas, durante um período determinado. Na prática, sua avaliação pode envolver disponibilidade, tolerância a falhas, recuperabilidade e comportamento diante de condições degradadas. Esses conceitos se relacionam, mas não são sinônimos.</p><p>Disponibilidade trata da prontidão do serviço para uso. Tolerância a falhas trata da capacidade de continuar entregando o comportamento requerido quando determinados componentes falham. Recuperabilidade considera como o sistema retorna a uma condição operacional adequada. Durabilidade diz respeito à preservação dos dados confirmados. Consistência e atomicidade também são preocupações importantes, especialmente quando operações atravessam fronteiras transacionais ou serviços distintos.</p><p>Uma análise arquitetural precisa separar níveis conceituais. O atributo de qualidade define o resultado desejado. A preocupação arquitetural delimita o risco que pode comprometer esse resultado. O requisito transforma a expectativa em um critério verificável. Táticas descrevem respostas possíveis, padrões organizam soluções recorrentes e tecnologias oferecem meios concretos de implementação. Essa separação evita transformar a avaliação em uma lista de produtos ou frameworks.</p><h3>Idempotência: repetir sem multiplicar efeitos</h3><p>Idempotência é uma propriedade especialmente relevante em integrações, APIs e processamento assíncrono. Uma operação idempotente pode ser executada mais de uma vez com o mesmo identificador ou contexto lógico sem produzir efeitos adicionais após a primeira execução bem-sucedida. O objetivo não é impedir tentativas repetidas, mas garantir que a repetição não provoque duplicidade.</p><p>Considere uma solicitação de pagamento. O serviço recebe o pedido e efetiva a transação, mas a resposta se perde por um timeout. A aplicação cliente não sabe se o pagamento ocorreu e tenta novamente. Sem um mecanismo de idempotência, a segunda tentativa pode gerar uma nova cobrança. Com uma chave estável, o serviço reconhece que aquela intenção de negócio já foi processada e devolve o resultado associado à operação original.</p><p>A implementação exige mais do que gerar um UUID. É necessário definir o escopo da chave, sua associação ao solicitante e à operação, o período de retenção, o comportamento para requisições concorrentes e a persistência do resultado. Também é importante decidir o que acontece quando a mesma chave chega com um payload diferente. Em geral, a chave deve identificar uma intenção de negócio, e não apenas uma tentativa de transporte.</p><p>O direcionamento arquitetural consiste em estabelecer uma identidade única para operações críticas, registrar de forma durável o estado e o resultado do processamento e tratar requisições repetidas de maneira determinística. Isso acrescenta armazenamento, controle de concorrência e políticas de expiração. O custo precisa ser comparado ao impacto potencial de duplicidades, principalmente em operações financeiras, pedidos, reservas e provisionamentos.</p><h3>Outbox Pattern: consistência entre estado e publicação</h3><p>O Transactional Outbox Pattern complementa a idempotência em arquiteturas orientadas a eventos. Ele endereça um problema clássico: uma aplicação atualiza seu banco de dados e publica um evento em um broker. Se a gravação for confirmada, mas a publicação falhar, ou vice-versa, o estado do sistema e o fluxo de eventos podem divergir.</p><p>Com Outbox, a alteração de negócio e o registro do evento a publicar são gravados na mesma transação local. Um processo separado lê os registros pendentes e os encaminha ao broker. Assim, a intenção de publicar o evento fica persistida junto com a mudança de estado. A publicação ainda pode ocorrer mais de uma vez, por exemplo quando o processo falha depois de publicar e antes de marcar o registro como concluído. Por isso, consumidores idempotentes continuam sendo necessários.</p><p>Esse ponto é essencial: Outbox não elimina duplicidade na entrega e não substitui idempotência. O padrão reduz o risco de perder a correspondência entre a transação local e a publicação do evento. A deduplicação no consumidor, normalmente baseada em um identificador único do evento ou da operação, trata as entregas repetidas. O trade-off envolve latência adicional, armazenamento dos registros, operação do processo de publicação e cuidados com ordenação e monitoramento.</p><h3>Isolamento de falhas: impedir que o problema se propague</h3><p>Tolerância a falhas não significa que todos os componentes continuarão funcionando normalmente. Significa que a arquitetura foi desenhada para que determinadas falhas não comprometam todo o sistema. Uma preocupação central é o isolamento de falhas (fault isolation), que limita o raio de impacto de uma indisponibilidade ou sobrecarga.</p><p>O Bulkhead Pattern aplica essa ideia por meio da segregação de recursos. Pools de threads, limites de concorrência, filas ou conexões podem ser separados por dependência ou domínio funcional. Se uma integração ficar lenta e consumir todos os recursos compartilhados, outras capacidades críticas também podem ser afetadas. Com a compartimentação, a saturação de uma área fica mais contida. O custo é administrar limites e capacidade separados, evitando tanto o esgotamento quanto a ociosidade excessiva.</p><p>O Circuit Breaker atua de maneira complementar. Ao observar falhas ou lentidão acima de limites definidos, interrompe temporariamente as chamadas a uma dependência e permite que ela se recupere. Ele não reserva recursos como o Bulkhead e não o substitui. O Bulkhead limita o consumo e o raio de impacto, enquanto o Circuit Breaker evita insistir em chamadas que provavelmente falharão. A combinação pode aumentar a resiliência, mas exige calibrar limiares, janelas de observação e condições de retomada para reduzir falsos positivos ou interrupções desnecessárias.</p><h3>Retry, timeout e controle de sobrecarga</h3><p>Retries são úteis para falhas transitórias, mas precisam ser projetados. Repetições ilimitadas ou sincronizadas podem amplificar uma indisponibilidade, criando uma tempestade de requisições. Uma política adequada combina limite de tentativas, backoff exponencial, jitter e classificação dos erros que realmente justificam nova tentativa. Retry em operações com efeitos colaterais exige idempotência.</p><p>Timeouts impedem que chamadas aguardem indefinidamente. Devem refletir o orçamento de latência da operação e ser coordenados entre camadas. Quando possível, deadlines devem ser propagados para que serviços downstream não continuem trabalhando em uma solicitação que já perdeu sua utilidade para o chamador. Um timeout, contudo, não prova que a operação não foi executada. O resultado pode ser desconhecido, reforçando a necessidade de idempotência e de consulta do estado da operação.</p><p>Esses mecanismos precisam ser avaliados em conjunto. Um retry pode consumir capacidade adicional justamente quando uma dependência está sob pressão. Um timeout muito curto pode interromper operações válidas, enquanto um timeout longo mantém recursos ocupados. A decisão deve considerar o comportamento esperado da dependência, o orçamento de latência, a criticidade da operação e a capacidade disponível.</p><h3>DLQ e recuperação operacional</h3><p>Uma Dead Letter Queue (DLQ) oferece um destino controlado para mensagens que não puderam ser processadas após as políticas definidas de tentativa ou que foram consideradas inválidas. Ela evita que uma mensagem problemática bloqueie indefinidamente o fluxo principal e permite investigação e reprocessamento consciente.</p><p>A DLQ não deve ser tratada como depósito definitivo de mensagens esquecidas. É necessário definir alertas, métricas, responsáveis, critérios de classificação, retenção, inspeção da causa e procedimento de replay. Antes de reprocessar, deve-se avaliar se o estado de negócio ainda permite a operação e se o consumidor é idempotente. Reprocessar sem controle pode reproduzir o problema ou gerar efeitos duplicados.</p><h3>Outras preocupações que completam a análise</h3><p>Atomicidade e consistência transacional exigem identificar operações que não podem deixar efeitos parciais e mapear suas fronteiras. Em fluxos distribuídos, pode ser necessário avaliar Saga, ações compensatórias e consistência eventual, sem presumir que uma transação ACID atravesse todos os serviços. A escolha traz complexidade de coordenação e exige tratar explicitamente estados intermediários e compensações.</p><p>Durabilidade e persistência exigem verificar quando uma operação é considerada confirmada, quais garantias de persistência existem e como backups, replicação e recuperação protegem os dados. Reconciliação complementa essas garantias ao comparar estados entre sistemas e detectar operações pendentes, divergentes ou incompletas. Ela é especialmente importante quando não existe uma transação distribuída única capaz de manter todos os participantes sincronizados.</p><p>Detecção e observabilidade tornam o comportamento compreensível. Logs, métricas e traces devem ser correlacionados por identificadores de operação e evento. Indicadores como quantidade de retries, timeouts, mensagens na DLQ, idade dos registros da Outbox, duplicidades detectadas e tempo de recuperação ajudam a identificar falhas e avaliar se os mecanismos estão funcionando como esperado.</p><p>Também é necessário definir a degradação controlada: quais capacidades podem operar parcialmente quando uma dependência falha, quais funções devem ser suspensas e como comunicar o estado degradado. Por fim, recuperação e continuidade precisam estabelecer objetivos de recuperação, procedimentos de failover, restauração e replay. Um mecanismo não testado é apenas uma hipótese de recuperação.</p><h3>Dos cenários de falha aos direcionamentos arquiteturais</h3><p>As recomendações devem estar vinculadas ao risco observado, e não à preferência por determinado padrão. Quando o cenário envolve duplicidade em operações críticas, o direcionamento pode ser uma chave estável, persistência do resultado e controle de concorrência. Quando há risco de perda entre o commit e a publicação, Outbox e consumidores idempotentes ajudam a preservar a correspondência entre estado e evento. Se o problema é uma dependência lenta ou indisponível, timeout, retry limitado, Circuit Breaker e Bulkhead podem ser combinados conforme o perfil da dependência.</p><p>Para mensagens que falham repetidamente, a resposta pode envolver política de retry, DLQ, alertas, investigação e replay controlado. Quando há divergência de estado entre serviços, entram em avaliação Saga, compensações, estados explícitos de processamento e reconciliação. Já falhas difíceis de diagnosticar apontam para propagação de correlation IDs e instrumentação de métricas, logs e traces de ponta a ponta. Cada direcionamento traz consequências: mais armazenamento, latência, complexidade operacional, consistência eventual, custo de telemetria ou risco de reprocessamento. Esses efeitos precisam ser explicitados na decisão.</p><h3>Como conectar aos trade-offs arquiteturais</h3><p>No contexto de arquitetura, a confiabilidade deve funcionar como o atributo de qualidade que orienta a investigação. A partir dele, os cenários de falha são traduzidos em preocupações arquiteturais e critérios verificáveis. Só então são avaliadas táticas e padrões. A tecnologia aparece por último, como alternativa de implementação, e não como ponto de partida.</p><p>Uma ficha de decisão pode registrar o direcionador de negócio, como evitar cobrança duplicada ou manter pedidos disponíveis, o cenário de falha, o atributo e a preocupação de qualidade, o requisito mensurável, como taxa máxima de duplicidade ou tempo máximo de recuperação, as alternativas arquiteturais, os trade-offs, a decisão e sua justificativa e as evidências obtidas por testes, métricas ou exercícios de falha.</p><p>Essa abordagem também evita recomendações genéricas. Nem todo serviço precisa de todos os padrões. A escolha depende da criticidade da operação, do custo de falha, do perfil de tráfego, das garantias necessárias, da topologia de dependências e da capacidade operacional da equipe. O mesmo mecanismo pode ser adequado em um contexto e desnecessário em outro.</p><h3>Tecnologias e mecanismos como camada de implementação</h3><p>A seleção tecnológica deve ocorrer depois que os requisitos e os direcionamentos estiverem claros. Em mensageria e eventos, soluções como Apache Kafka, RabbitMQ, Amazon SQS e SNS, Azure Service Bus e Google Pub/Sub podem oferecer recursos para transporte, filas, particionamento e integração com processos de Outbox e DLQ. A escolha depende das garantias de entrega, ordenação, operação e escala exigidas pelo fluxo.</p><p>Na persistência, PostgreSQL e MySQL podem apoiar transações locais, restrições de unicidade e registros de idempotência. Redis também pode ser considerado em determinados cenários, desde que suas garantias de durabilidade e consistência sejam avaliadas com cuidado. Para resiliência na aplicação, bibliotecas como Resilience4j, Spring Retry e Polly ajudam a implementar retry limitado, backoff, timeout e Circuit Breaker, mas não substituem a definição arquitetural das políticas.</p><p>Na observabilidade, OpenTelemetry, Prometheus, Grafana, Jaeger e plataformas comerciais de APM podem apoiar métricas, logs estruturados, traces distribuídos e correlação. Kubernetes e mecanismos de health check, readiness e limites de recursos contribuem para reinício, isolamento e escalabilidade da execução. Entretanto, orquestração não substitui a resiliência da aplicação nem resolve automaticamente problemas de consistência, idempotência ou recuperação de negócio. As ferramentas são meios para implementar e operar decisões, não garantias de confiabilidade por si só.</p><h3>Considerações finais</h3><p>Confiabilidade é uma propriedade construída por decisões coordenadas. Idempotência reduz os efeitos de repetições, o Outbox protege a relação entre a transação local e a publicação de eventos, o Bulkhead limita o raio de impacto, o Circuit Breaker evita insistência em dependências degradadas, timeout e retry controlam a execução, DLQ e reconciliação apoiam a recuperação e observabilidade torna o comportamento verificável.</p><p>O valor arquitetural não está em adotar todos esses mecanismos, mas em reconhecer os cenários que ameaçam o negócio, estabelecer as garantias necessárias e escolher respostas proporcionais. Quando os direcionamentos são registrados junto aos trade-offs, a arquitetura deixa de ser uma coleção de padrões e passa a ser um conjunto explícito de decisões justificadas, verificáveis e evolutivas.</p><h3>Referências para aprofundamento</h3><ul><li>ISO/IEC 25010:2023 — Systems and software engineering — Systems and software Quality Requirements and Evaluation (SQuaRE) — Product quality model.</li><li>Martin Kleppmann. Designing Data-Intensive Applications. O’Reilly Media, 2017.</li><li>Chris Richardson. Microservices Patterns. Manning, 2018.</li><li>Microsoft. Cloud Design Patterns — Retry, Circuit Breaker, Bulkhead e padrões relacionados.</li><li>microservices.io — Transactional Outbox pattern e Idempotent Consumer pattern.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=216c3ed568ea" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Da Intenção ao Sistema: domínio, dados, distribuição e evolução com fundamentos que conectam as…]]></title>
            <link>https://medium.com/@marcelomg21/da-inten%C3%A7%C3%A3o-ao-sistema-dom%C3%ADnio-dados-distribui%C3%A7%C3%A3o-e-evolu%C3%A7%C3%A3o-com-fundamentos-que-conectam-as-c510892d405f?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/c510892d405f</guid>
            <category><![CDATA[event-driven-architecture]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[arquitectura-de-software]]></category>
            <category><![CDATA[fault-tolerance]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Tue, 03 Nov 2026 15:39:34 GMT</pubDate>
            <atom:updated>2026-11-03T15:40:04.031Z</atom:updated>
            <content:encoded><![CDATA[<h3>Da Intenção ao Sistema: domínio, dados, distribuição e evolução com fundamentos que conectam as decisões arquiteturais</h3><p>Desde os primeiros textos sobre <strong>Event-Driven Architecture (EDA)</strong>, <strong>Domain-Driven Design (DDD)</strong> e <strong>CQRS</strong>, uma questão atravessa diferentes discussões sobre arquitetura de software: como organizar um sistema para representar corretamente o negócio, preservar suas regras, distribuir responsabilidades e continuar evoluindo quando o contexto muda? A primeira vista, esses assuntos parecem pertencer a áreas distintas. Um trata de comunicação, outro de modelagem de domínio, outro de leitura e escrita de dados. Quando observados em conjunto, porém, revelam partes de um mesmo problema.</p><p>A arquitetura não começa pela escolha de microsserviços, bancos, brokers ou frameworks. Começa pela compreensão do problema e das propriedades que a solução precisa preservar. <strong>O desenho técnico é consequência de decisões sobre significado, responsabilidade, consistência e mudança.</strong> Essa perspectiva permite conectar conceitos que acompanham a evolução das arquiteturas distribuídas e que continuam relevantes mesmo quando as tecnologias mudam.</p><h3>O domínio define o significado antes da tecnologia definir a estrutura</h3><p>Em <strong>Domain-Driven Design</strong>, Eric Evans desloca o foco da modelagem para a complexidade do domínio. O software precisa representar conceitos, regras e relações que façam sentido para quem conhece o negócio. A linguagem ubíqua não é apenas um glossário compartilhado. É um mecanismo para reduzir ambiguidades entre especialistas, equipes e implementação. Um mesmo termo pode ter significados diferentes em contextos distintos. Por isso, o <strong>Bounded Context</strong> estabelece uma fronteira semântica na qual determinado modelo é válido.</p><p>Essa fronteira tem consequências arquiteturais. Ela ajuda a definir responsabilidades, contratos e ownership dos dados. Dentro do contexto, agregados protegem invariantes que precisam ser preservadas em uma unidade consistente. O agregado não deve ser entendido como um agrupamento arbitrário de entidades, mas como uma fronteira de consistência e de acesso ao estado. A regra de negócio indica o que precisa permanecer íntegro. O desenho do agregado organiza essa garantia.</p><p>É nesse ponto que modelagem de domínio e arquitetura distribuída se encontram. <strong>Nem todo limite de negócio precisa ser um microsserviço, mas todo serviço deveria possuir uma responsabilidade compreensível e limites explícitos.</strong> Distribuir componentes antes de compreender o domínio apenas transforma ambiguidades internas em dependências remotas. Modularização e distribuição são decisões diferentes. Um monólito modular pode preservar bons limites sem introduzir imediatamente os custos de uma rede entre processos.</p><h3>Comandos, eventos e dados: representar o que o sistema faz e o que aconteceu</h3><p>Os textos sobre CQRS e Event Sourcing aprofundam uma mudança importante na forma de pensar os dados. Em vez de enxergar o sistema apenas como um conjunto de operações CRUD sobre entidades, passamos a distinguir <strong>intenções de mudança</strong> dos <strong>fatos produzidos por essas mudanças</strong>. Um comando expressa o que alguém deseja que aconteça. Um evento registra algo que efetivamente aconteceu. Essa diferença é semântica, mas também organiza o fluxo de responsabilidades.</p><p><strong>CQRS (Command Query Responsibility Segregation)</strong> separa os modelos usados para alterar o estado daqueles usados para consultá-lo. A separação pode ser lógica, sem exigir bancos distintos ou serviços separados. Seu valor aparece quando as necessidades de escrita e leitura são diferentes, quando o domínio de escrita possui regras complexas ou quando as cargas precisam evoluir de forma independente. Como alerta Martin Fowler, CQRS não é uma solução padrão para qualquer aplicação. Em domínios simples, a separação pode adicionar mais complexidade do que benefício.</p><p>Quando combinado com DDD, o modelo de escrita pode direcionar comandos aos agregados, preservando invariantes em suas fronteiras. O modelo de leitura, por sua vez, pode oferecer projeções ajustadas às consultas e às necessidades de apresentação. Se essas projeções forem atualizadas de forma assíncrona, surge a <strong>consistência eventual</strong>. Ela não significa ausência de consistência, mas a aceitação de que diferentes representações podem permanecer temporariamente defasadas. O negócio precisa definir onde essa defasagem é aceitável e onde uma garantia mais forte é indispensável.</p><p>Event Sourcing leva a ideia adiante ao persistir a sequência de eventos que produziu o estado, em vez de armazenar somente a última versão da entidade. O estado atual pode ser reconstruído pela aplicação dos eventos, eventualmente a partir de snapshots. Isso favorece auditoria, reconstrução histórica e novas projeções. Entretanto, exige cuidado com versionamento de eventos, evolução de esquemas, reprocessamento e compatibilidade. <strong>Event Sourcing não é sinônimo de EDA, assim como CQRS não exige Event Sourcing.</strong> São conceitos que podem se combinar, mas resolvem problemas diferentes.</p><h3>EDA distribui reações, mas não elimina a coordenação</h3><p>Na arquitetura orientada a eventos, produtores publicam fatos relevantes e consumidores reagem a eles sem precisarem conhecer diretamente uns aos outros. Essa independência reduz o acoplamento temporal e permite estender o ecossistema com novos consumidores. Coreografia distribui a coordenação entre participantes. Orquestração mantém um coordenador explícito para conduzir o fluxo. Nenhuma das duas é universalmente superior. A escolha depende da visibilidade desejada, da complexidade do processo e da necessidade de controlar seu ciclo de vida.</p><p>Também é importante distinguir o evento como fato de negócio do mecanismo usado para transportá-lo. Message brokers, event brokers e abordagens brokerless oferecem propriedades diferentes de entrega, retenção, replay, ordenação e recuperação. Kafka, RabbitMQ, NATS ou comunicação direta não são decisões arquiteturais por si só. São alternativas de implementação que precisam responder a requisitos explícitos. <strong>A tecnologia não define sozinha as garantias do sistema.</strong></p><h3>Distribuir responsabilidades significa distribuir também as falhas</h3><p>A comunicação assíncrona reduz dependências temporais, mas introduz estados intermediários. Mensagens podem ser duplicadas, atrasadas ou reprocessadas. Consumidores podem falhar depois de executar uma operação e antes de confirmar seu processamento. Um timeout não prova que a operação remota não aconteceu. Apenas informa que a resposta não chegou dentro do prazo esperado. Por isso, idempotência, correlação, deduplicação, observabilidade e recuperação precisam fazer parte do desenho.</p><p>Essa realidade conecta EDA à discussão sobre transações distribuídas. Dentro de uma fronteira local, mecanismos ACID oferecem garantias valiosas. Quando uma operação atravessa serviços e bancos independentes, a atomicidade global passa a exigir coordenação e introduz custos de disponibilidade, latência e operação. Sagas, compensações, outbox transacional e reconciliação ajudam a lidar com fluxos que não podem depender de uma única transação abrangendo todo o ecossistema. Compensar não é apagar o passado. É executar uma nova ação de negócio que restabeleça um estado aceitável.</p><p>A <strong>granularidade transacional</strong> torna essa discussão ainda mais concreta. Qual conjunto de mudanças precisa acontecer junto para preservar uma invariante? O que pode avançar de forma independente? Uma transação mais espessa pode simplificar determinadas garantias, mas concentrar contenção e ampliar o impacto de falhas. Transações menores favorecem autonomia, mas exigem coordenação explícita entre etapas. O menor grão possível não é necessariamente o melhor. O objetivo é encontrar a menor unidade que preserve as invariantes necessárias sem impor custos desproporcionais de coordenação.</p><p>Joe Armstrong e a filosofia de Erlang ajudam a reforçar outra dimensão: falhas não devem ser tratadas como exceções improváveis. Isolamento, supervisão e recuperação reconhecem que componentes podem falhar sem que o sistema inteiro precise falhar junto. <strong>Resiliência é uma propriedade do sistema</strong>, não uma característica isolada de uma biblioteca, de um container ou de uma instância redundante. Ela emerge da combinação entre aplicação, dados, infraestrutura, comunicação e operação.</p><h3>Atributos de qualidade transformam preferências em decisões</h3><p>Desempenho, disponibilidade, segurança, escalabilidade, confiabilidade e modificabilidade não devem aparecer apenas como adjetivos em documentos. Precisam ser traduzidos em cenários verificáveis. Qual latência é aceitável? Qual volume deve ser suportado? Quanto tempo de indisponibilidade é tolerável? Que atraso de dados o negócio aceita? Quais operações precisam manter consistência imediata? Sem critérios, a escolha entre REST e eventos, monólito e microsserviços, broker e brokerless tende a ser guiada por preferência tecnológica.</p><p>É aqui que os direcionadores de negócio se convertem em direcionadores arquiteturais. O upstream esclarece problema, restrições, riscos e atributos prioritários. O downstream materializa decisões em componentes, contratos, padrões, testes e operação. Esse processo não é linear. Evidências de produção, testes de carga, incidentes e mudanças no negócio devem retroalimentar as decisões. O registro de decisões arquiteturais (ADRs) preserva contexto, alternativas, trade-offs e consequências, evitando que escolhas importantes dependam apenas da memória das pessoas.</p><h3>Arquitetura vive no tempo: precisa evoluir sem perder suas propriedades</h3><p>Uma arquitetura não permanece adequada apenas porque nasceu de boas decisões. O negócio muda, a carga cresce, novas integrações aparecem e tecnologias deixam de atender às necessidades. Neal Ford, Rebecca Parsons e Patrick Kua descrevem arquiteturas evolucionárias como estruturas que permitem mudanças incrementais e guiadas em múltiplas dimensões. Essa visão desloca a arquitetura de um desenho produzido no início para uma capacidade contínua de orientar e validar mudanças.</p><p>As <strong>fitness functions arquiteturais</strong> ajudam a proteger características importantes durante essa evolução. Podem verificar dependências proibidas entre módulos, limites de latência, padrões de segurança, contratos ou regras de implantação. Testes automatizados, métricas, monitoramento e análise estática são mecanismos possíveis. O essencial é transformar uma intenção arquitetural em uma propriedade observável. Uma diretriz que não pode ser verificada corre o risco de permanecer apenas documental.</p><p>Essa abordagem também esclarece o papel do arquiteto. Seu trabalho não é antecipar todas as mudanças nem centralizar cada decisão. É compreender o negócio, definir limites, explicitar trade-offs, apoiar as equipes e garantir que as propriedades essenciais sejam preservadas enquanto o sistema evolui. A arquitetura precisa aproximar-se da engenharia porque é na implementação e na operação que suas hipóteses são confrontadas com a realidade.</p><p>A chegada de agentes de inteligência artificial torna essa responsabilidade ainda mais relevante. Agentes podem analisar código, propor alternativas, implementar mudanças e executar testes com velocidade crescente. Mas uma alteração localmente correta pode ampliar acoplamento, enfraquecer segurança ou violar uma invariante de negócio. Quanto maior a capacidade de execução, maior a importância de fornecer contexto, limites, critérios de aceitação e mecanismos de validação. A IA pode acelerar a exploração e a implementação. Não elimina a necessidade de escolher o que deve ser construído nem de assumir as consequências.</p><h3>Considerações finais</h3><p>Observados em conjunto, DDD, CQRS, Event Sourcing, EDA, sistemas distribuídos, granularidade transacional, trade-offs e arquiteturas evolucionárias não são assuntos isolados. Eles descrevem dimensões complementares de um mesmo exercício: <strong>organizar responsabilidades em torno do domínio, preservar invariantes, distribuir trabalho e dados com garantias explícitas e permitir que o sistema mude sem perder aquilo que é essencial.</strong></p><p>A maturidade arquitetural não está na quantidade de padrões adotados nem no grau de distribuição alcançado. Está na capacidade de reconhecer o problema, compreender as propriedades necessárias e escolher estruturas proporcionais ao contexto. Às vezes, a melhor decisão será um monólito modular. Em outras, eventos, projeções separadas ou serviços independentes farão sentido. O que diferencia uma decisão fundamentada de uma escolha por tendência é a clareza sobre seus motivos, custos e consequências.</p><p>No fim, arquitetura de software é menos sobre desenhar componentes e mais sobre estabelecer relações que continuem fazendo sentido ao longo do tempo. É decidir o que precisa permanecer junto, o que pode evoluir separadamente, quais falhas precisam ser absorvidas e quais compromissos o negócio está disposto a assumir.</p><blockquote>Uma boa arquitetura não elimina a complexidade. Ela a organiza, limita seus efeitos e torna sua evolução possível.</blockquote><h3>Referências e leituras relacionadas</h3><p><strong>GONÇALVES, Marcelo M. </strong>Event-driven Architecture (EDA) em uma Arquitetura de Microsserviços (2019). <br><a href="https://medium.com/sicreditech/event-driven-architecture-eda-em-uma-arquitetura-de-micro-servi%C3%A7os-1981614cdd45">https://medium.com/sicreditech/event-driven-architecture-eda-em-uma-arquitetura-de-micro-servi%C3%A7os-1981614cdd45</a></p><p><strong>GONÇALVES, Marcelo M. </strong>Domain-driven Design (DDD) em uma Arquitetura de Microsserviços (2019). <br><a href="https://medium.com/@marcelomg21/domain-driven-design-ddd-em-uma-arquitetura-de-micro-servi%C3%A7os-cac52a90a40">https://medium.com/@marcelomg21/domain-driven-design-ddd-em-uma-arquitetura-de-micro-servi%C3%A7os-cac52a90a40</a></p><p><strong>GONÇALVES, Marcelo M. </strong>CQRS em uma Arquitetura de Microsserviços (2020). <br><a href="https://medium.com/@marcelomg21/cqrs-command-query-responsibility-segregation-em-uma-arquitetura-de-micro-servi%C3%A7os-71dcb687a8a9">https://medium.com/@marcelomg21/cqrs-command-query-responsibility-segregation-em-uma-arquitetura-de-micro-servi%C3%A7os-71dcb687a8a9</a></p><p><strong>GONÇALVES, Marcelo M. </strong>Event-sourcing (ES) em uma Arquitetura de Microsserviços (2020). <a href="https://medium.com/@marcelomg21/event-sourcing-es-em-uma-arquitetura-de-micro-servi%C3%A7os-852f6ce04595">https://medium.com/@marcelomg21/event-sourcing-es-em-uma-arquitetura-de-micro-servi%C3%A7os-852f6ce04595</a></p><p><strong>EVANS, Eric. </strong>Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2003. <br><a href="https://books.google.com/books?id=hHBf4YxMnWMC">https://books.google.com/books?id=hHBf4YxMnWMC</a></p><p><strong>FOWLER, Martin. </strong>CQRS (2011) e Event Sourcing. <a href="https://www.martinfowler.com/bliki/CQRS.html">https://www.martinfowler.com/bliki/CQRS.html</a></p><p><strong>KLEPPMANN, Martin. </strong>Designing Data-Intensive Applications. O’Reilly, 2017. <br><a href="https://dataintensive.net/">https://dataintensive.net/</a></p><p><strong>FORD, Neal, PARSONS, Rebecca, KUA, Patrick. </strong>Building Evolutionary Architectures. O’Reilly, 2017. <br><a href="https://nealford.com/books/buildingevolutionaryarchitectures.html">https://nealford.com/books/buildingevolutionaryarchitectures.html</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c510892d405f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Arquiteturas Distribuídas: resiliência, tolerância a falhas e dados]]></title>
            <link>https://medium.com/@marcelomg21/arquiteturas-distribu%C3%ADdas-resili%C3%AAncia-toler%C3%A2ncia-a-falhas-e-dados-9ab01d97fc99?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/9ab01d97fc99</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[sistemas-distribuidos]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <category><![CDATA[arquitetura-distribuida]]></category>
            <category><![CDATA[arquitetura-de-dados]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Fri, 30 Oct 2026 19:02:49 GMT</pubDate>
            <atom:updated>2026-10-30T19:02:49.335Z</atom:updated>
            <content:encoded><![CDATA[<p>Sistemas distribuídos tornaram-se parte da estrutura de praticamente todas as soluções digitais relevantes. Aplicações que antes concentravam processamento e persistência em um único ambiente passaram a combinar serviços, bancos de dados, filas, mecanismos de streaming, caches e plataformas especializadas. Essa composição permite escalar partes da solução de forma independente e atender diferentes padrões de acesso. Entretanto, distribuir componentes não significa, por si só, construir um sistema mais resiliente ou eficiente. A distribuição amplia as possibilidades, mas também introduz falhas parciais, latência, concorrência, inconsistência e maior complexidade operacional.</p><p>Em Designing Data-Intensive Applications, Martin Kleppmann organiza esses desafios a partir de uma perspectiva fundamentalmente arquitetural. O foco não está em escolher uma tecnologia específica, mas em compreender as propriedades que os sistemas precisam oferecer e os mecanismos pelos quais essas propriedades são construídas. Essa distinção é importante: escalabilidade, confiabilidade e capacidade de evolução não são características que surgem automaticamente da adoção de microsserviços, bancos distribuídos ou processamento assíncrono. Elas dependem de decisões explícitas sobre responsabilidades, dados, comunicação e comportamento diante de falhas.</p><p>A discussão pode ser organizada em três dimensões complementares: primeiro, os fundamentos de confiabilidade e tolerância a falhas e depois, a distribuição dos dados por meio de replicação, particionamento e consistência. Por fim, a construção e manutenção de dados derivados, que conectam diferentes modelos de armazenamento e processamento.</p><h3>Confiabilidade começa pelo reconhecimento da falha</h3><p>Uma arquitetura confiável não é aquela em que todos os componentes funcionam o tempo todo. É aquela que continua oferecendo o comportamento esperado, dentro de limites conhecidos, mesmo quando parte de seus componentes falha. Essa diferença muda a forma de projetar. Em vez de tratar a falha como uma exceção improvável, precisamos considerá-la uma condição normal de operação.</p><p>É útil distinguir falha de componente e falha do sistema. Um disco pode apresentar defeito, uma instância pode ser encerrada, uma rede pode perder pacotes ou um serviço pode responder lentamente. Esses eventos são falhas de componentes. O sistema falha quando deixa de cumprir o serviço esperado. Redundância, replicação, recuperação e degradação controlada são mecanismos para impedir que uma falha localizada se transforme em indisponibilidade ampla.</p><p>Também é importante separar falhas de hardware, erros de software e falhas humanas. Hardware tende a apresentar defeitos relativamente previsíveis em escala. Software pode falhar de maneira correlacionada, por exemplo, quando uma mesma versão contém um bug que afeta todas as instâncias. Erros humanos incluem configurações incorretas, exclusões acidentais e operações executadas no ambiente errado. Cada classe exige controles diferentes. Replicar servidores ajuda contra a perda de uma máquina, mas não protege necessariamente contra uma atualização defeituosa replicada para todas elas.</p><p>A arquitetura deve, portanto, explicitar como detecta falhas, como limita sua propagação e como recupera o estado. Timeouts, retentativas, circuit breakers, isolamento de recursos, filas, limites de concorrência, backups testados e procedimentos de restauração não são apenas detalhes operacionais. São partes do desenho de confiabilidade. Retentativas sem controle, por exemplo, podem amplificar uma sobrecarga e produzir uma falha em cascata. Uma estratégia resiliente precisa considerar backoff, jitter, idempotência e limites para o número de tentativas.</p><h3>Escalabilidade não é apenas adicionar máquinas</h3><p>Escalabilidade descreve a capacidade de um sistema lidar com o crescimento da carga sem que o custo ou a degradação de desempenho aumentem de forma descontrolada. Para discutir esse atributo, é necessário caracterizar a carga: quantidade de requisições, volume de dados, proporção entre leitura e escrita, distribuição de acessos, tamanho das mensagens e padrões de concorrência. Sem métricas e cenários concretos, dizer que uma solução precisa escalar pouco ajuda a orientar decisões.</p><p>A escala vertical aumenta os recursos de uma máquina. A escala horizontal distribui a carga entre várias máquinas. A segunda oferece maior elasticidade e pode melhorar a disponibilidade, mas exige que o sistema lide com coordenação, comunicação remota, distribuição de dados e falhas parciais. O custo de uma chamada entre processos é diferente do custo de uma chamada local. Uma sequência de chamadas síncronas entre serviços pode transformar pequenas latências individuais em uma latência relevante para a experiência completa.</p><p>Outro ponto é a assimetria da carga. Uma distribuição aparentemente uniforme pode esconder chaves muito acessadas, clientes dominantes ou períodos de pico. O particionamento pode distribuir dados e processamento, mas uma chave quente continua concentrando trabalho em uma partição. Escalar exige entender o padrão real de uso e observar o comportamento do sistema, não apenas aumentar a quantidade de instâncias.</p><h3>Dados distribuídos: replicação, particionamento e consistência</h3><p>A replicação mantém cópias dos mesmos dados em diferentes nós. Ela pode melhorar a disponibilidade, aproximar os dados dos consumidores e aumentar a capacidade de leitura. Em contrapartida, introduz o problema de manter as réplicas suficientemente atualizadas. Em modelos com um líder, as escritas são encaminhadas a um nó principal e propagadas aos seguidores. Em modelos com múltiplos líderes ou sem líder, a distribuição das escritas muda, mas também aumenta a complexidade de resolução de conflitos e de ordenação.</p><p>A escolha não deve ser feita apenas pelo desempenho nominal. É preciso definir o que o negócio considera aceitável quando uma réplica está atrasada, quando uma região fica isolada ou quando duas atualizações concorrentes ocorrem. Consistência forte pode simplificar certas garantias para o consumidor, mas tende a exigir coordenação e pode aumentar a latência ou reduzir a disponibilidade em determinadas condições. Consistência eventual pode favorecer disponibilidade e desempenho, desde que o domínio aceite observar temporariamente estados diferentes.</p><p>O particionamento, ou sharding, divide um conjunto de dados em partes distribuídas entre nós. Seu objetivo é permitir que armazenamento e processamento cresçam horizontalmente. A estratégia de particionamento influencia distribuição de carga, localidade, consultas e reequilíbrio. Particionar por uma chave inadequada pode gerar partições desiguais, consultas que atravessam muitos nós e pontos de concentração. A chave deve considerar os padrões de acesso, a cardinalidade, a distribuição dos valores e as operações que precisam permanecer próximas.</p><p>Replicação e particionamento resolvem problemas diferentes e frequentemente são combinados. O particionamento distribui conjuntos distintos de dados. A replicação mantém cópias de cada conjunto. Em conjunto, permitem escalar capacidade e tolerar a perda de nós, mas não eliminam a necessidade de definir consistência, recuperação, ordenação e comportamento durante falhas.</p><p>Transações também precisam ser compreendidas nesse contexto. Dentro de um único banco, propriedades ACID oferecem garantias valiosas de atomicidade, consistência, isolamento e durabilidade. Quando uma operação atravessa vários serviços ou bancos independentes, a coordenação se torna mais complexa. A arquitetura precisa decidir onde a atomicidade é realmente indispensável, onde consistência eventual é aceitável e como tratar operações parcialmente concluídas. Padrões como saga, compensação, outbox transacional e processamento idempotente ajudam a construir fluxos confiáveis sem presumir que uma única transação global resolverá todos os problemas.</p><h3>Sistemas distribuídos também dependem de limites bem definidos</h3><p>A distribuição física dos componentes não deve ser confundida com uma boa separação de responsabilidades. Serviços excessivamente fragmentados aumentam a quantidade de interações remotas e tornam o comportamento global mais difícil de compreender. Serviços grandes demais, por outro lado, podem concentrar responsabilidades e dificultar a evolução independente. O limite adequado depende da coesão funcional, da propriedade dos dados, da autonomia necessária e dos requisitos de qualidade.</p><p>Uma decisão arquitetural relevante é estabelecer quem é responsável por cada dado e qual componente pode alterá-lo. Quando vários serviços escrevem diretamente nas mesmas tabelas, os limites de domínio ficam frágeis e a evolução se torna dependente de conhecimento compartilhado. A propriedade explícita dos dados reduz acoplamento e permite que contratos de integração sejam tratados como parte da arquitetura.</p><p>A comunicação síncrona é adequada quando a resposta imediata faz parte do requisito. A comunicação assíncrona pode desacoplar disponibilidade e ritmo entre produtores e consumidores, absorver picos e permitir processamento posterior. Contudo, introduz atrasos, duplicidade, reordenação e necessidade de observabilidade do fluxo. Não existe uma escolha universal. O desenho deve considerar o tempo de resposta esperado, a criticidade da operação, a tolerância a atrasos e a capacidade de recuperação.</p><h3>Dados derivados: integrar sem criar dependências frágeis</h3><p>Em arquiteturas modernas, um mesmo fato pode alimentar diferentes estruturas de dados. Uma base transacional atende às operações do negócio, enquanto um índice de busca, um cache, uma visão materializada ou um modelo analítico atende a padrões de leitura específicos. Esses conjuntos são dados derivados: são construídos a partir de uma fonte ou fluxo de mudanças e organizados para uma finalidade.</p><p>A especialização permite escolher estruturas adequadas a cada padrão de acesso. O problema arquitetural está em manter essas representações coerentes. Atualizar banco, índice de busca e cache como se fossem uma única transação distribuída costuma criar dependências frágeis. Se uma das etapas falhar, o sistema pode ficar parcialmente atualizado. Uma alternativa mais robusta é tratar as mudanças como um fluxo durável, propagá-las de forma assíncrona e tornar os consumidores idempotentes.</p><p>Change Data Capture (CDC) permite capturar alterações realizadas em uma base e publicá-las para outros consumidores. Event sourcing adota uma perspectiva diferente, registrando eventos de domínio como histórico de fatos aceitos. Em ambos os casos, logs e fluxos podem servir como base para reconstruir projeções e alimentar sistemas derivados. É essencial, porém, distinguir eventos de negócio de registros técnicos de alteração. Um evento como ‘pedido confirmado’ expressa um fato do domínio. Uma alteração de coluna informa que determinado registro foi modificado.</p><p>A reconstrução é uma propriedade arquitetural valiosa. Se um índice ou uma projeção estiver inconsistente, deve ser possível reprocessar o fluxo ou executar uma carga de reconstrução a partir de uma fonte confiável. Isso exige versionamento de esquemas, compatibilidade entre produtores e consumidores, controle de offsets, tratamento de mensagens inválidas e mecanismos para acompanhar atrasos. Dados derivados não devem se tornar uma segunda fonte de verdade por acidente.</p><p>Processamento em lote e processamento de fluxo atendem necessidades diferentes e complementares. O lote processa conjuntos finitos de dados, sendo útil para recomputação, consolidação e correção histórica. O fluxo reage continuamente a eventos, oferecendo menor latência para atualização. A arquitetura pode combinar os dois, desde que defina como resultados são reconciliados, como reprocessamentos são realizados e qual atraso é aceitável para cada consumidor.</p><p>A ideia central é substituir a expectativa de sincronismo absoluto por um fluxo de dados explícito, observável e recuperável. Isso não significa aceitar inconsistência sem controle. Significa definir a fonte de verdade, estabelecer garantias por consumidor e criar meios de detectar e corrigir divergências.</p><h3>Observabilidade e verificabilidade como parte do desenho</h3><p>Uma arquitetura resiliente precisa tornar seu comportamento visível. Métricas de latência, taxa de erro, saturação, disponibilidade, atraso de replicação, lag de consumidores, taxa de retentativas e tamanho de filas ajudam a identificar degradações antes que se transformem em incidentes amplos. Logs estruturados e rastreamento distribuído complementam as métricas ao permitir reconstruir o caminho de uma requisição entre serviços.</p><p>Também é necessário verificar as garantias prometidas. Backups precisam ser restaurados em testes. Failovers precisam ser exercitados. Consumidores devem ser testados contra duplicidade e reordenação. Reprocessamentos devem produzir resultados consistentes. Testes de carga precisam considerar distribuição desigual e picos, não apenas médias. Uma propriedade arquitetural que não pode ser observada ou testada corre o risco de existir apenas no documento de arquitetura.</p><h3>Considerações finais</h3><p>Projetar sistemas distribuídos é, acima de tudo, administrar consequências. Replicar dados melhora determinadas formas de disponibilidade, mas exige lidar com defasagem e conflitos. Particionar permite distribuir capacidade, mas torna consultas e operações globais mais complexas. Processar eventos de forma assíncrona reduz dependências temporais, mas introduz duplicidade, ordenação e consistência eventual. Especializar armazenamentos melhora a adequação aos padrões de acesso, mas exige uma estratégia confiável para manter os dados derivados.</p><p>A contribuição mais importante de uma abordagem fundamentada como a de Martin Kleppmann é deslocar a discussão da tecnologia para as propriedades do sistema. Antes de escolher um banco, broker ou framework, precisamos compreender a carga, os cenários de falha, as garantias de consistência e os limites de recuperação que o negócio exige. A partir daí, as decisões deixam de ser escolhas isoladas e passam a formar uma arquitetura coerente.</p><p>Resiliência não é ausência de falhas. É a capacidade de absorvê-las, limitar seus efeitos e recuperar o funcionamento sem comprometer a integridade do negócio. Escalabilidade não é simplesmente adicionar nós. É distribuir carga e dados sem criar gargalos e dependências desproporcionais. E integração de dados não é manter cópias idênticas em tempo real a qualquer custo. É construir fluxos explícitos, rastreáveis e recuperáveis entre diferentes representações.</p><p>No fim, uma boa arquitetura distribuída não é aquela que elimina toda complexidade, algo que raramente é possível. É aquela que reconhece onde a complexidade existe, estabelece limites para ela e torna seus trade-offs conscientes. É isso que permite construir sistemas capazes de crescer, falhar parcialmente, se recuperar e continuar evoluindo.</p><h3>Referências</h3><p><strong>KLEPPMANN, Martin. </strong>Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems. O’Reilly Media, 2017.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9ab01d97fc99" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Arquitetura e a Espessura Transacional: granularidade, falhas e evolução em sistemas distribuídos]]></title>
            <link>https://medium.com/@marcelomg21/a-arquitetura-e-a-espessura-transacional-granularidade-falhas-e-evolu%C3%A7%C3%A3o-em-sistemas-distribu%C3%ADdos-c5b6d46abd39?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/c5b6d46abd39</guid>
            <category><![CDATA[modulariadadearquitetural]]></category>
            <category><![CDATA[granularidadetransacional]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[distributed-transaction]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Wed, 28 Oct 2026 14:00:22 GMT</pubDate>
            <atom:updated>2026-10-28T14:00:22.356Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>O tamanho da transação é uma decisão arquitetural</strong></h3><p>Quando falamos de transações, é comum pensar primeiro em atomicidade, consistência e mecanismos de commit ou rollback. Mas existe uma pergunta anterior, mais estrutural: qual é o grão daquilo que precisa acontecer junto?</p><p>A granularidade transacional define o conjunto de mudanças que o sistema trata como uma única unidade de trabalho. Sua espessura representa, de forma intuitiva, quanto comportamento, estado e responsabilidade ficam concentrados dentro dessa unidade. Uma transação fina coordena poucas mudanças. Uma transação espessa tenta garantir que várias mudanças, possivelmente em diferentes módulos ou serviços, aconteçam como se fossem uma única operação.</p><p>Não existe um tamanho universalmente correto. A escolha depende do significado de negócio, dos atributos de qualidade exigidos e do custo de coordenar componentes. O erro é tratar essa decisão como um detalhe de implementação, quando ela influencia acoplamento, disponibilidade, desempenho, tolerância a falhas e capacidade de evolução.</p><h3>Da fronteira de negócio à fronteira transacional</h3><p>O ponto de partida deve ser a regra de negócio, não a tecnologia. Uma compra, por exemplo, pode envolver reserva de estoque, autorização de pagamento, emissão de nota e solicitação de entrega. Do ponto de vista do usuário, tudo isso pode parecer uma única operação. Do ponto de vista arquitetural, são responsabilidades distintas, com tempos de execução e modos de falha diferentes.</p><p>A pergunta relevante é quais invariantes precisam ser preservadas imediatamente e quais efeitos podem ocorrer de forma assíncrona. Se duas mudanças precisam ser inseparáveis para manter uma regra essencial, há uma razão forte para mantê-las na mesma fronteira transacional. Se um efeito pode ser confirmado depois, com estados intermediários explícitos e mecanismos de recuperação, talvez seja melhor separá-lo.</p><p>Isso não significa que toda fronteira de negócio deva virar um serviço, nem que toda chamada entre serviços exija uma transação distribuída. Modularização e distribuição são decisões diferentes. Um módulo pode preservar uma transação local sem ser implantado separadamente. Separar processos e bancos de dados altera o problema porque introduz comunicação, latência, falhas parciais e incerteza sobre o estado dos participantes.</p><h3>Transações distribuídas: consistência tem um custo</h3><p>Em uma transação local, o banco de dados normalmente oferece mecanismos maduros para confirmar ou desfazer um conjunto de alterações. Em uma transação distribuída, a coordenação atravessa fronteiras que podem falhar de maneira independente. A rede pode ficar indisponível, uma resposta pode se perder depois de o comando ter sido executado e um participante pode ficar inacessível enquanto os demais continuam funcionando.</p><p>Protocolos como two-phase commit podem oferecer coordenação forte em determinados cenários, mas trazem custos de disponibilidade, bloqueio e operação. Em outros contextos, uma saga divide o fluxo em transações locais e define ações compensatórias para lidar com falhas. A compensação, porém, não é um rollback mágico. Enviar uma mercadoria de volta, estornar um pagamento ou cancelar uma reserva são novas operações de negócio, sujeitas às próprias regras e falhas.</p><p>A escolha não é simplesmente entre consistência e desempenho. É uma decisão sobre quais garantias são necessárias, por quanto tempo o sistema pode permanecer em um estado intermediário e como esse estado será observado, recuperado e explicado. Idempotência, retentativas controladas, timeouts, filas de mensagens, reconciliação e rastreabilidade deixam de ser acessórios. Passam a fazer parte do desenho transacional.</p><h3>Atributos de qualidade moldam o grão</h3><p>Granularidade é um ponto de encontro entre atributos de qualidade. Aumentar a espessura pode reduzir o número de etapas visíveis e simplificar certas garantias locais. Ao mesmo tempo, pode ampliar a duração da transação, o tempo de bloqueio, a contenção e o impacto de uma falha. Transações mais finas podem melhorar isolamento, escalabilidade e autonomia dos componentes, mas também aumentam a necessidade de coordenação e tratamento de estados intermediários.</p><p>Desempenho não é apenas latência média. Inclui throughput, contenção, uso de recursos e comportamento sob carga. Disponibilidade não significa somente manter o processo no ar. Significa conseguir oferecer a capacidade necessária quando dependências falham. Confiabilidade envolve preservar invariantes e recuperar-se de estados inesperados. Segurança também importa: cada fronteira pode exigir autenticação, autorização, validação e proteção contra repetição de comandos.</p><p>Esses atributos entram em tensão. Uma decisão que reduz latência pode aumentar a complexidade de recuperação. Uma garantia de consistência mais forte pode limitar a disponibilidade durante determinadas falhas. A arquitetura precisa tornar esses trade-offs explícitos, conectando direcionadores de negócio a requisitos arquiteturais, alternativas, consequências e evidências. Não basta afirmar que uma solução é mais resiliente ou escalável. É preciso dizer sob quais condições e a que custo.</p><h3>Integradores e desintegradores de granularidade</h3><p>Alguns mecanismos integram o fluxo e tornam a transação conceitualmente mais espessa. Uma transação ACID local, uma chamada síncrona encadeada ou um coordenador central podem concentrar etapas em uma única sequência de execução. Isso pode ser adequado quando a regra exige resposta imediata e as dependências têm limites operacionais conhecidos. Mas também pode criar acoplamento temporal: se uma dependência demora ou falha, toda a operação sente o efeito.</p><p>Outros mecanismos desintegram o fluxo em unidades menores. Eventos, filas, processamento assíncrono, sagas e limites de contexto bem definidos permitem que partes do processo avancem de forma independente. A separação reduz algumas dependências, mas exige contratos claros, correlação entre mensagens, idempotência, observabilidade e políticas para mensagens duplicadas ou fora de ordem.</p><p>Esses mecanismos não são bons ou ruins por natureza. São integradores ou desintegradores do grão transacional conforme o modo como conectam responsabilidades. Uma chamada síncrona pode ser apropriada dentro de uma fronteira coesa. Um evento pode ser inadequado quando o negócio exige confirmação imediata de uma invariante. A decisão deve seguir a semântica da operação e os atributos de qualidade, não uma preferência geral por síncrono, assíncrono, monólito ou microsserviços.</p><h3>Modularização e tolerância a falhas</h3><p>A modularização ajuda a definir onde as responsabilidades começam e terminam. Um bom módulo reúne decisões que mudam juntas e esconde detalhes que não deveriam ser conhecidos pelos consumidores. Contratos explícitos reduzem o acoplamento estrutural. Porém, modularizar não elimina automaticamente o acoplamento comportamental. Se um módulo só consegue operar quando outro responde imediatamente, existe uma dependência temporal, mesmo que as interfaces estejam bem desenhadas.</p><p>A tolerância a falhas começa por reconhecer que falhas parciais são normais em sistemas distribuídos. Timeouts precisam ser acompanhados de uma política de retentativa. Retentativas precisam considerar idempotência e risco de amplificar uma sobrecarga. Circuit breakers podem conter chamadas repetidamente malsucedidas, enquanto filas podem absorver variações de carga. Nenhum desses mecanismos substitui a definição do estado de negócio após uma falha.</p><p>A pergunta central é: quando uma etapa falha, qual parte do sistema deve parar, qual pode continuar e como o processo será retomado? A resposta determina o grão operacional da transação. Quanto maior a unidade indivisível, maior pode ser o raio de impacto. Quanto mais fragmentado o fluxo, maior pode ser o custo de coordenação e reconciliação.</p><h3>Arquitetura evolucionária: o grão não é imutável</h3><p>O grão transacional adequado hoje pode deixar de ser adequado amanhã. O volume pode crescer, uma dependência externa pode se tornar instável, uma regra regulatória pode mudar ou uma nova experiência pode exigir menor latência. Arquitetura evolucionária parte do reconhecimento de que decisões devem poder ser revistas sem perder de vista as garantias essenciais.</p><p>Fitness functions arquiteturais ajudam a verificar continuamente propriedades relevantes. Elas podem acompanhar latência em percentis, taxa de falhas, tempo de recuperação, duplicidade de processamento, atraso de eventos e violações de invariantes. Esses sinais permitem avaliar se a granularidade escolhida continua atendendo aos objetivos. ADRs, por sua vez, registram contexto, alternativas, trade-offs e consequências para que a decisão não dependa apenas da memória de quem a tomou.</p><p>A evolução não exige fragmentar tudo desde o início. É possível começar com uma transação local bem delimitada, observar os limites reais e separar responsabilidades quando houver evidência. Também é possível consolidar componentes que foram distribuídos cedo demais. A arquitetura evolui quando consegue mudar a estrutura preservando comportamento, contratos e critérios de qualidade.</p><h3>Considerações finais</h3><p>A granularidade transacional conecta semântica de negócio, modularização, consistência, desempenho, disponibilidade e tolerância a falhas. Ela define não apenas o que acontece junto, mas também o que pode falhar separadamente, o que precisa ser compensado e o que pode evoluir de forma independente.</p><p>Transações espessas podem simplificar certas garantias, mas concentrar dependências e ampliar o impacto de falhas. Transações finas podem favorecer autonomia e escala, mas exigem coordenação explícita, observabilidade e recuperação bem projetada. A melhor escolha não é a menor nem a maior transação. É o menor grão que preserva as invariantes necessárias sem impor custos desproporcionais de coordenação.</p><p>A arquitetura de software se torna mais consistente quando essas escolhas são tratadas como decisões explícitas, fundamentadas em direcionadores de negócio e verificadas ao longo do tempo. O objetivo não é eliminar trade-offs, mas torná-los compreensíveis, mensuráveis e revisáveis.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c5b6d46abd39" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Trade-offs Arquiteturais na era dos Agentes de IA]]></title>
            <link>https://medium.com/@marcelomg21/trade-offs-arquiteturais-na-era-dos-agentes-de-ia-7cba587f5b02?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/7cba587f5b02</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[arquitetura-evolucionaria]]></category>
            <category><![CDATA[agentes-de-ia]]></category>
            <category><![CDATA[ia-agents]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Tue, 27 Oct 2026 10:42:00 GMT</pubDate>
            <atom:updated>2026-10-27T10:42:00.267Z</atom:updated>
            <content:encoded><![CDATA[<p>Durante muito tempo, uma parte importante do trabalho de arquitetura de software esteve concentrada em decisões tomadas antes da implementação. A partir dos objetivos de negócio, dos requisitos e dos atributos de qualidade prioritários, definimos limites, responsabilidades, integrações, mecanismos de resiliência e os trade-offs que a solução precisa aceitar.</p><p>Essa lógica continua válida. O que muda com os agentes de inteligência artificial é que parte do comportamento do sistema deixa de estar completamente definida em tempo de projeto. Um agente pode selecionar ferramentas, escolher caminhos e ajustar sua estratégia conforme o contexto e os resultados intermediários. A arquitetura passa a lidar não apenas com a estrutura do sistema, mas também com os limites das decisões que ele pode tomar durante a execução.</p><p>Isso não significa que os trade-offs deixaram de ser decisões de arquitetura ou que tudo precise ser decidido em tempo real. Significa que precisamos distinguir aquilo que deve permanecer como uma restrição arquitetural daquilo que pode variar dentro de limites previamente estabelecidos.</p><h3>Da decomposição de serviços à decomposição de decisões</h3><p>Microsserviços ajudaram a decompor sistemas por capacidades e responsabilidades. Contratos explícitos, limites de domínio e fluxos definidos permitem que serviços evoluam de forma relativamente independente. Mesmo quando a execução é distribuída, o caminho principal costuma estar representado no código ou no mecanismo de orquestração.</p><p>Em sistemas agênticos, a sequência de ações pode ser escolhida dinamicamente. Diante de um objetivo, o agente pode consultar uma fonte, invocar uma ferramenta, avaliar o resultado e decidir qual passo executar em seguida. A complexidade não desaparece. Parte dela se desloca da coordenação de serviços para a coordenação de decisões.</p><p>Essa distinção, explorada por Mallika Rao na InfoQ, não deve ser interpretada como uma substituição universal dos microsserviços. Agentes podem operar sobre serviços existentes, enquanto operações críticas continuam determinísticas. A questão arquitetural é decidir onde a adaptação gera valor e onde a previsibilidade é mais importante.</p><h3>O que muda nos trade-offs arquiteturais</h3><p>Um trade-off representa uma escolha entre propriedades que não podem ser maximizadas simultaneamente, ou que impõem custos diferentes. Em sistemas tradicionais, muitas dessas escolhas são avaliadas no upstream: antes da construção, com base nos direcionadores de negócio, nos requisitos e nos riscos conhecidos. Em sistemas agênticos, essa análise continua necessária, mas precisa incluir decisões sobre o espaço de autonomia permitido durante a operação.</p><p>Considere autonomia versus controle. Mais liberdade pode permitir que o agente responda melhor a situações imprevistas. Ao mesmo tempo, amplia a variabilidade, dificulta a previsão de custos e pode aumentar o risco de ações inadequadas. A decisão não deve ser simplesmente permitir ou proibir autonomia. É necessário definir quais ações são permitidas, quais exigem aprovação e quais devem permanecer fora do alcance do agente.</p><p>Outro trade-off é adaptabilidade versus previsibilidade. A seleção dinâmica de ferramentas pode melhorar a resposta a diferentes contextos, mas também faz com que duas solicitações semelhantes sigam caminhos diferentes. Para operações financeiras, segurança ou alterações irreversíveis, talvez seja preferível manter etapas determinísticas. Em tarefas exploratórias ou de apoio à análise, um grau maior de adaptação pode ser aceitável.</p><p>Há ainda custo versus qualidade. Ciclos de avaliação e novas tentativas podem melhorar um resultado, mas aumentam latência, consumo de recursos e carga sobre os serviços envolvidos. Limites de tempo, orçamento, tentativas e critérios de encerramento são, portanto, decisões arquiteturais e operacionais, não detalhes que podem ser deixados exclusivamente ao agente.</p><h3>Decidir antes e governar durante a execução</h3><p>A arquitetura não deve tentar antecipar todas as decisões que um agente poderá tomar. Isso seria incompatível com a própria ideia de comportamento adaptativo. Seu papel é estabelecer o espaço dentro do qual a adaptação pode ocorrer.</p><p>No upstream, definimos os objetivos, os riscos aceitáveis, os atributos de qualidade prioritários e as fronteiras de autonomia. Também identificamos decisões que precisam ser determinísticas, ações que exigem autorização humana e condições em que o sistema deve interromper a execução ou recorrer a um caminho alternativo.</p><p>Em runtime, o sistema aplica esses limites e coleta evidências sobre seu comportamento. Políticas de acesso, orçamentos de execução, limites de tentativas, validações de saída e mecanismos de fallback reduzem o risco de que uma decisão local produza consequências desproporcionais. Quando o contexto muda ou as evidências mostram que uma premissa deixou de ser válida, a arquitetura pode precisar ser revista.</p><blockquote>Não se trata de substituir decisões de upstream por decisões em tempo real. Trata-se de combinar decisões estruturais tomadas antecipadamente com mecanismos de controle e avaliação que funcionam continuamente.</blockquote><h3>Observabilidade: além da saúde técnica</h3><p>Latência, disponibilidade, throughput e taxa de erros continuam sendo métricas essenciais. Porém, um sistema agêntico pode permanecer tecnicamente saudável e ainda produzir resultados piores. A degradação pode aparecer na escolha inadequada de ferramentas, no uso de contexto desatualizado, no aumento de tentativas ou na propagação de uma decisão incorreta.</p><p>Por isso, a observabilidade precisa acompanhar a qualidade dos resultados e o caminho que levou a eles. É importante registrar chamadas de ferramentas, transferências entre agentes, resultados intermediários, tentativas, uso de mecanismos alternativos e avaliações de qualidade. Esses dados ajudam a distinguir uma falha de infraestrutura de uma falha na decisão.</p><p>A avaliação também precisa ser tratada como parte do ciclo de engenharia. Testes com cenários representativos, avaliações contínuas e implantações graduais permitem identificar regressões antes de ampliar a autonomia. Como as respostas de modelos podem variar, a validação nem sempre deve depender de correspondência textual exata. Critérios de qualidade, limites e evidências precisam ser definidos de acordo com o risco do caso de uso.</p><h3>Arquitetura evolucionária e limites verificáveis</h3><p>A abordagem se conecta à arquitetura evolucionária. Não precisamos acertar antecipadamente cada comportamento, mas precisamos tornar verificáveis as propriedades que não podem se deteriorar silenciosamente. Testes automatizados, políticas, métricas e verificações de arquitetura podem funcionar como fitness functions, ajudando a identificar quando uma mudança viola um limite importante.</p><p>Por exemplo, podemos verificar que um agente não invoque ferramentas fora de sua permissão, que uma operação de alto impacto exija aprovação, que a execução respeite um orçamento de custo ou que resultados abaixo de um critério mínimo sejam encaminhados para revisão. Essas verificações não eliminam o julgamento arquitetural. Elas transformam parte das expectativas em controles observáveis.</p><p>Também é importante evitar a complexidade desnecessária. Nem todo problema precisa de agentes, e nem todo sistema agêntico precisa ser multiagente. Quando um fluxo determinístico resolve o problema com menor custo e risco, essa pode continuar sendo a melhor solução. A escolha deve partir do problema de negócio e dos trade-offs, não da novidade tecnológica.</p><h3>Considerações finais</h3><p>Os agentes de IA não eliminam os fundamentos da arquitetura de software. Eles ampliam o conjunto de decisões que precisamos governar. Limites de contexto, contratos, segurança, resiliência e observabilidade continuam importantes, mas passam a conviver com a necessidade de avaliar decisões que podem variar durante a execução.</p><p>Os trade-offs, portanto, não deixam de ser definidos no upstream. O que muda é que algumas decisões arquiteturais passam a estabelecer limites para escolhas posteriores, realizadas em runtime. A autonomia pode variar dentro desse espaço, enquanto segurança, custo, qualidade e confiabilidade precisam ser medidos continuamente.</p><p>O papel do arquiteto não é prever cada caminho que o agente seguirá. É definir quais caminhos são aceitáveis, quais consequências precisam ser evitadas e quais evidências demonstram que o sistema continua cumprindo seus objetivos. A arquitetura deixa de ser apenas o desenho de componentes e fluxos e passa a incluir a governança do comportamento dinâmico.</p><blockquote>A pergunta central não é quanto de autonomia podemos conceder. É quanto de autonomia podemos conceder sem perder o controle das propriedades que tornam o sistema útil, seguro e confiável.</blockquote><h3>Referências</h3><p>• Rao, Mallika. “From Microservices to Agents: the Next Evolution of Distributed Systems.” InfoQ, 19 out. 2026. <a href="https://www.infoq.com/articles/distributed-systems-microservices-agentic-ai/">https://www.infoq.com/articles/distributed-systems-microservices-agentic-ai/</a></p><p>• Amazon Web Services. “Agentic AI Patterns and Workflows.” AWS Prescriptive Guidance. <a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/agentic-ai-patterns/">https://docs.aws.amazon.com/prescriptive-guidance/latest/agentic-ai-patterns/</a></p><p>• Google Cloud. “Choose a design pattern for your agentic AI system.” Cloud Architecture Center, revisão de 28 mai. 2026. <a href="https://docs.cloud.google.com/architecture/choose-design-pattern-agentic-ai-system">https://docs.cloud.google.com/architecture/choose-design-pattern-agentic-ai-system</a></p><p>• Microsoft. “AI Agent Orchestration Patterns.” Azure Architecture Center. <a href="https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/ai-agent-design-patterns">https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/ai-agent-design-patterns</a></p><p>• NIST. “Artificial Intelligence Risk Management Framework: Generative Artificial Intelligence Profile.” NIST AI 600–1, 2024. <a href="https://www.nist.gov/publications/artificial-intelligence-risk-management-framework-generative-artificial-intelligence">https://www.nist.gov/publications/artificial-intelligence-risk-management-framework-generative-artificial-intelligence</a></p><p>• Rao, Mallika. “From Microservices to Agents: the Next Evolution of Distributed Systems.” InfoQ, 19 out. 2026. <a href="https://www.infoq.com/articles/distributed-systems-microservices-agentic-ai/">https://www.infoq.com/articles/distributed-systems-microservices-agentic-ai/</a></p><p>• Amazon Web Services. “Agentic AI Patterns and Workflows.” AWS Prescriptive Guidance. <a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/agentic-ai-patterns/">https://docs.aws.amazon.com/prescriptive-guidance/latest/agentic-ai-patterns/</a></p><p>• Google Cloud. “Choose a design pattern for your agentic AI system.” Cloud Architecture Center, revisão de 28 mai. 2026. <a href="https://docs.cloud.google.com/architecture/choose-design-pattern-agentic-ai-system">https://docs.cloud.google.com/architecture/choose-design-pattern-agentic-ai-system</a></p><p>• Microsoft. “AI Agent Orchestration Patterns.” Azure Architecture Center. <a href="https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/ai-agent-design-patterns">https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/ai-agent-design-patterns</a></p><p>• NIST. “Artificial Intelligence Risk Management Framework: Generative Artificial Intelligence Profile.” NIST AI 600–1, 2024. <a href="https://www.nist.gov/publications/artificial-intelligence-risk-management-framework-generative-artificial-intelligence">https://www.nist.gov/publications/artificial-intelligence-risk-management-framework-generative-artificial-intelligence</a></p><p>• Ford, Neal; Parsons, Rebecca; Kua, Patrick. “Building Evolutionary Architectures.” O’Reilly Media, 2017.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7cba587f5b02" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Arquitetura de Software vive no Tempo: evolução, ruptura e o desafio de continuar relevante…]]></title>
            <link>https://medium.com/@marcelomg21/arquitetura-de-software-vive-no-tempo-evolu%C3%A7%C3%A3o-ruptura-e-o-desafio-de-continuar-relevante-7a03bce9659e?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/7a03bce9659e</guid>
            <category><![CDATA[architectural-trade-offs]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Mon, 26 Oct 2026 13:04:57 GMT</pubDate>
            <atom:updated>2026-10-26T20:13:23.015Z</atom:updated>
            <content:encoded><![CDATA[<h3>Arquitetura de Software vive no Tempo: evolução, ruptura e o desafio de continuar relevante enquanto o contexto muda</h3><p>A arquitetura de software vive no tempo. Ela não existe apenas no instante em que desenhamos componentes, escolhemos um estilo arquitetural ou registramos uma decisão. Ela continua existindo enquanto o sistema é construído, operado, ampliado e transformado. E, durante esse percurso, sofre os efeitos do próprio tempo.</p><p>O negócio muda, o volume cresce, novas integrações surgem, equipes se reorganizam e tecnologias antes adequadas podem deixar de responder às necessidades. Uma decisão que parecia correta no início pode se tornar uma restrição. Uma solução simples pode acumular exceções. Uma arquitetura que atendia ao contexto original pode deixar de atender ao contexto atual. O tempo não é apenas o cenário onde a arquitetura existe. É uma força que altera suas condições de validade.</p><h3>A arquitetura não é uma fotografia</h3><p>É tentador tratar arquitetura como uma fotografia do sistema: um conjunto de diagramas, padrões e decisões que representa como a solução deveria funcionar. Mas a fotografia registra apenas um momento. O sistema real é um filme, e cada mudança acrescenta um novo capítulo à sua história.</p><p>Com o passar do tempo, as decisões acumulam consequências. Algumas continuam úteis, outras precisam ser revistas e algumas passam a limitar a evolução. Acoplamentos que pareciam inofensivos tornam mudanças caras. Contratos evoluem em ritmos diferentes. Atalhos de implementação se transformam em dependências difíceis de remover. É assim que a arquitetura pode degradar sem que exista uma única decisão claramente errada: pequenas concessões, repetidas ao longo do tempo, alteram a estrutura e o custo de mudança.</p><p>Isso não significa que toda arquitetura envelhece mal ou que decisões duradouras sejam um problema. O ponto é outro: uma decisão arquitetural deve ser compreendida dentro do contexto e das premissas que a justificaram. Quando essas premissas mudam, a decisão merece ser reavaliada.</p><h3>Evoluir não é mudar por mudar</h3><p>A arquitetura evolutiva, discutida por <strong>Neal Ford, Rebecca Parsons, Patrick Kua</strong> e, na segunda edição, <strong>Pramod Sadalage</strong>, parte de uma ideia prática: permitir mudanças incrementais e orientadas, preservando características arquiteturais importantes. Evoluir não significa aceitar qualquer alteração nem perseguir novidade tecnológica. Significa criar condições para que o sistema mude sem perder de vista aquilo que precisa continuar verdadeiro.</p><p>Se o negócio exige maior volume de transações, a arquitetura pode precisar evoluir em escalabilidade e desempenho. Se novas regras surgem com frequência, modularidade e testabilidade ganham importância. Se a operação exige recuperação rápida, resiliência e observabilidade deixam de ser preocupações secundárias. O direcionador de negócio ajuda a revelar o atributo de qualidade prioritário, e esse atributo orienta as decisões e seus trade-offs.</p><p>A contribuição de <strong>Mark Richards e Neal Ford</strong> em tratar arquitetura como disciplina de engenharia também é relevante: decisões não devem se apoiar apenas em preferências ou diagramas elegantes. Precisam considerar consequências, restrições, custos operacionais e evidências. Uma arquitetura evolutiva não prevê todas as mudanças futuras. Ela evita depender dessa previsão.</p><h3>Ruptura: quando evoluir aos poucos já não basta</h3><p>Nem toda transformação cabe em uma sequência confortável de pequenos ajustes. Às vezes, o contexto muda de forma tão significativa que a arquitetura precisa de uma ruptura: substituir um componente central, alterar o modelo de integração, separar responsabilidades antes concentradas ou até migrar para outro estilo arquitetural.</p><p>Ruptura não é sinônimo de fracasso. Pode ser o reconhecimento de que as premissas originais deixaram de existir. O erro é tanto insistir em uma estrutura que já não serve quanto promover uma reescrita ampla sem demonstrar por que ela é necessária. A decisão deve comparar alternativas, custo de transição, riscos, compatibilidade, capacidade da equipe e valor esperado. Em muitos casos, uma migração gradual reduz o risco. Em outros, manter a arquitetura atual custa mais do que transformá-la.</p><p>A pergunta relevante não é <strong>“qual arquitetura é melhor?”</strong>, de forma abstrata. É <strong>“qual arquitetura responde melhor às necessidades atuais e mantém um caminho sustentável para as necessidades que provavelmente virão?”</strong>. A resposta pode mudar com o tempo, porque o contexto e os trade-offs também mudam.</p><h3>Como tornar a evolução verificável</h3><p>Para que evolução não seja apenas uma intenção, precisamos tornar explícitas as propriedades que não podem se deteriorar silenciosamente. Testes automatizados, métricas, monitoramento, análise de dependências e verificações no pipeline podem funcionar como architectural fitness functions. Elas ajudam a avaliar, de forma objetiva, se uma mudança preserva atributos importantes ou viola limites estabelecidos.</p><p>Por exemplo, uma equipe pode verificar automaticamente que módulos de domínio não dependam da camada de infraestrutura, que endpoints críticos respeitem um orçamento de latência ou que uma alteração de contrato não quebre consumidores conhecidos. Essas verificações não substituem o julgamento arquitetural. Elas tornam visíveis algumas consequências e permitem corrigir o rumo antes que pequenas degradações se acumulem.</p><p>Também é importante registrar o contexto, as alternativas consideradas e os trade-offs aceitos (<strong>ADR</strong> — <strong>Architecture Decision Record</strong>). Quando as premissas mudarem, esse registro ajuda a entender por que a decisão foi tomada e se ela continua válida. Arquitetura evolui melhor quando decisões podem ser examinadas à luz de evidências, não apenas defendidas por terem sido tomadas no passado.</p><h3>Considerações finais</h3><p>Dizer que a arquitetura de software vive no tempo é reconhecer que ela está submetida à mudança e que seu valor depende da capacidade de continuar respondendo ao contexto. Ela sofre quando decisões antigas se tornam restrições, quando a dívida arquitetural cresce sem visibilidade e quando a estrutura deixa de acompanhar o negócio. Mas também amadurece quando a equipe aprende com a operação, revê premissas e transforma mudanças em parte consciente da engenharia.</p><p>A arquitetura não precisa permanecer igual para continuar íntegra. Precisa preservar o que é essencial, adaptar o que perdeu sentido e romper com o que já não serve. O objetivo não é construir hoje uma estrutura perfeita para um futuro desconhecido. É construir um sistema capaz de evoluir com direção, validar suas decisões e mudar de forma sustentável.</p><blockquote>A arquitetura não é uma promessa de permanência. É uma capacidade de continuar relevante enquanto o mundo ao redor muda.</blockquote><h3>Referências para aprofundamento</h3><p>• Neal Ford, Rebecca Parsons e Patrick Kua — Building Evolutionary Architectures: <a href="https://nealford.com/books/buildingevolutionaryarchitectures.html">https://nealford.com/books/buildingevolutionaryarchitectures.html</a></p><p>• Neal Ford, Rebecca Parsons, Patrick Kua e Pramod Sadalage — Building Evolutionary Architectures, 2nd edition: <a href="https://nealford.com/books/bea2e.html">https://nealford.com/books/bea2e.html</a></p><p>• Mark Richards e Neal Ford — Fundamentals of Software Architecture: An Engineering Approach: <a href="https://nealford.com/books/softwarearchitecturefundamentals.html">https://nealford.com/books/softwarearchitecturefundamentals.html</a></p><p>• Thoughtworks — Building Evolutionary Architectures: <a href="https://www.thoughtworks.com/insights/books/building-evolutionary-architectures">https://www.thoughtworks.com/insights/books/building-evolutionary-architectures</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a03bce9659e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fitness Functions: tornando a arquitetura evolucionária verificável]]></title>
            <link>https://medium.com/@marcelomg21/fitness-functions-tornando-a-arquitetura-evolucion%C3%A1ria-verific%C3%A1vel-16c3c14bf059?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/16c3c14bf059</guid>
            <category><![CDATA[fitness-function]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <category><![CDATA[architecture-trade-offs]]></category>
            <category><![CDATA[arquitetura-evolucionária]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Thu, 22 Oct 2026 12:59:05 GMT</pubDate>
            <atom:updated>2026-10-22T12:59:05.646Z</atom:updated>
            <content:encoded><![CDATA[<p>Arquiteturas não permanecem adequadas apenas porque nasceram de boas decisões. À medida que o negócio muda, novas funcionalidades são entregues e sistemas acumulam integrações, as decisões arquiteturais precisam continuar produzindo os resultados esperados.</p><p>É nesse contexto que as <em>fitness functions</em> ganham relevância. Elas permitem transformar intenções arquiteturais em verificações objetivas, executáveis e recorrentes, aproximando a arquitetura do processo real de desenvolvimento e operação.</p><h3>Da intenção à evidência</h3><p>O trabalho de arquitetura começa antes da escolha de frameworks, bancos de dados ou estilos de integração. No <em>upstream</em>, precisamos compreender os direcionadores de negócio: reduzir o tempo de lançamento, aumentar a conversão, atender exigências regulatórias, suportar o crescimento ou melhorar a experiência do cliente.</p><p>Esses objetivos são traduzidos em direcionadores arquiteturais e atributos de qualidade, como disponibilidade, desempenho, segurança, modificabilidade e interoperabilidade. O desafio é garantir que essas propriedades não permaneçam apenas como requisitos documentados ou decisões registradas em diagramas.</p><p>Uma arquitetura pode declarar que determinada API precisa responder rapidamente, que dados sensíveis devem permanecer protegidos ou que dois domínios precisam evoluir de maneira independente. Entretanto, uma nova integração, uma consulta sem índice ou uma dependência introduzida por conveniência pode comprometer essas propriedades sem que o problema seja identificado durante uma revisão de código.</p><p>As <em>fitness functions</em> ajudam a reduzir essa distância entre intenção e realidade. São mecanismos utilizados para verificar se uma solução continua atendendo a características arquiteturais relevantes. Podem assumir a forma de testes automatizados, regras estáticas, verificações no pipeline de entrega, consultas de observabilidade ou experimentos em ambientes controlados.</p><blockquote>O ponto central não é a ferramenta utilizada, mas a capacidade de conectar uma decisão arquitetural a uma evidência verificável.</blockquote><h3>A ponte entre negócio e arquitetura</h3><p>A ISO/IEC 25010 oferece uma referência para organizar características de qualidade, mas não substitui o entendimento do contexto de negócio. Desempenho, segurança e confiabilidade são conceitos amplos. Para orientar decisões, precisamos definir o que cada atributo representa para determinado sistema, em quais cenários será avaliado e quais limites são aceitáveis.</p><p>Considere uma plataforma de pagamentos cujo direcionador de negócio seja aumentar a aprovação das transações sem degradar a experiência do usuário. A arquitetura precisa considerar, entre outros fatores, a latência das integrações, a disponibilidade dos provedores, o comportamento diante de falhas e a capacidade de absorver variações de demanda.</p><p>A partir dessas decisões, podemos estabelecer verificações para medir percentis de latência sob carga, validar limites de <em>timeout</em> e <em>retry</em>, testar a indisponibilidade de um provedor e identificar dependências que aumentem o acoplamento entre domínios.</p><p>Cada verificação avalia uma parte da hipótese arquitetural. Nenhum indicador isolado, entretanto, representa o sucesso do negócio por completo. Essa distinção é importante: uma <em>fitness function</em> não deve existir apenas porque determinado atributo pode ser medido. Ela precisa existir porque a propriedade avaliada é relevante para uma decisão, um risco ou um resultado esperado.</p><h3>Transformando decisões arquiteturais em verificações</h3><p>Podemos relacionar diferentes intenções arquiteturais a mecanismos de verificação executáveis.</p><p><strong>Preservar o desempenho.</strong> Testes de carga em jornadas críticas podem avaliar latência, taxa de erros e <em>throughput</em>. Os resultados permitem identificar regressões introduzidas por mudanças no código, no banco de dados ou nas integrações.</p><p><strong>Reduzir o acoplamento.</strong> Regras automatizadas podem impedir dependências proibidas entre módulos ou domínios. Se uma alteração introduzir uma dependência que contrarie os limites arquiteturais definidos, o pipeline poderá sinalizar ou bloquear a mudança.</p><p><strong>Fortalecer a segurança.</strong> Verificações de dependências vulneráveis, exposição de segredos e configurações inseguras ajudam a identificar desvios antes que cheguem à produção. A abrangência e a severidade das regras devem refletir o risco do sistema.</p><p><strong>Aumentar a resiliência.</strong> Testes de falha podem verificar se o sistema se recupera de indisponibilidades, respeita limites de tentativas e evita que uma falha localizada provoque uma cascata de erros.</p><p><strong>Preservar a compatibilidade.</strong> Testes de contrato entre consumidores e provedores ajudam a garantir que mudanças nas interfaces não quebrem integrações existentes.</p><p>Esses exemplos mostram que as <em>fitness functions</em> podem atuar em diferentes níveis. Algumas são rápidas e executadas a cada <em>commit</em>. Outras dependem de ambientes integrados, testes de carga ou dados operacionais. A escolha deve considerar o risco arquitetural, o custo de execução e o tempo necessário para obter feedback.</p><h3>Observabilidade: verificando a arquitetura em produção</h3><p>Nem todas as propriedades arquiteturais podem ser avaliadas adequadamente durante a construção do software. Algumas dependem das condições reais de uso, do volume de tráfego, do comportamento de sistemas externos e da interação entre diferentes componentes.</p><p>Nesse cenário, métricas, logs e <em>traces</em> tornam-se fontes importantes de evidência. SLOs e indicadores de experiência ajudam a verificar se as premissas arquiteturais continuam válidas durante a operação.</p><p>É importante, contudo, diferenciar monitoramento de <em>fitness functions</em>. Um alerta indica que uma condição merece atenção. Uma <em>fitness function</em> estabelece uma propriedade que queremos preservar e define como avaliar sua conformidade.</p><p>Por exemplo, uma equipe pode estabelecer que determinada jornada crítica precisa permanecer dentro de um objetivo de latência. Uma verificação recorrente pode analisar a telemetria e identificar desvios. Se o limite for ultrapassado, o resultado deve provocar uma ação: investigar a causa, revisar a implementação ou reconsiderar a decisão arquitetural.</p><p>A operação passa, assim, a contribuir para a evolução da arquitetura, em vez de atuar apenas como uma etapa posterior à entrega.</p><h3>Trade-offs precisam ser explícitos</h3><p>Arquitetura é feita de trade-offs. Aumentar a redundância pode melhorar a disponibilidade, mas também elevar custos e complexidade. Adicionar validações de segurança pode aumentar a latência. Buscar maior <em>throughput</em> pode exigir processamento assíncrono e alterar as garantias de consistência percebidas pelos consumidores.</p><p>Por isso, as <em>fitness functions</em> não devem se transformar em uma coleção de métricas arbitrárias ou em uma tentativa de maximizar todos os atributos simultaneamente.</p><p>Cada limite precisa refletir uma prioridade de negócio, um cenário de uso e um risco aceitável. Quando a prioridade muda, a regra também pode precisar mudar, desde que a alteração seja deliberada, justificada e rastreável.</p><p>Também é necessário evitar verificações excessivamente rígidas. Uma regra que bloqueia mudanças legítimas, gera falsos positivos continuamente ou deixou de representar uma necessidade do negócio pode prejudicar a evolução do sistema.</p><blockquote>A função de uma <em>fitness function</em> não é impedir mudanças, mas ajudar a distinguir mudanças seguras de mudanças que comprometem propriedades importantes.</blockquote><h3>Como começar sem criar burocracia</h3><p>A adoção pode começar com um direcionador de negócio e uma hipótese arquitetural específica.</p><p>Primeiro, identifique uma jornada ou um risco relevante. Em seguida, formule a propriedade que precisa ser preservada, defina como ela será observada e estabeleça um critério de avaliação.</p><p>Por exemplo: se a arquitetura precisa evitar que a indisponibilidade de um provedor de pagamentos comprometa toda a plataforma, podemos criar testes que simulem falhas, avaliem o comportamento dos <em>timeouts</em> e <em>retries</em> e verifiquem se os mecanismos de isolamento funcionam conforme esperado.</p><p>A verificação deve ser incorporada ao ponto mais adequado do ciclo de entrega ou operação. Por fim, os resultados precisam ser revisados periodicamente para identificar lacunas, falsos positivos e mudanças de contexto.</p><p>O objetivo não é medir toda a arquitetura desde o primeiro dia. É começar pelas propriedades que representam maior risco ou valor para o negócio e ampliar a cobertura conforme a necessidade.</p><h3>Considerações finais</h3><p>Arquitetura evolucionária não significa mudar continuamente sem direção. Significa permitir que a solução evolua preservando — ou revisando conscientemente — as propriedades que sustentam seus objetivos.</p><p>As <em>fitness functions</em> aproximam arquitetura e engenharia porque levam decisões para o fluxo real de desenvolvimento e operação, onde podem ser verificadas repetidamente. Elas ajudam a transformar atributos de qualidade, restrições e decisões arquiteturais em mecanismos concretos de feedback.</p><p>Isso não elimina a necessidade de julgamento profissional, nem garante uma arquitetura adequada apenas pela existência de testes. Seu valor está em reduzir a distância entre o que declaramos importante e o que conseguimos observar.</p><p>Quando direcionadores de negócio, decisões arquiteturais, trade-offs e evidências estão conectados, a arquitetura deixa de depender exclusivamente da memória das equipes e passa a contar com mecanismos para verificar sua própria evolução.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=16c3c14bf059" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Message brokers, Event brokers e Brokerless: a decisão é arquitetural, não tecnológica]]></title>
            <link>https://medium.com/@marcelomg21/message-brokers-event-brokers-e-brokerless-a-decis%C3%A3o-%C3%A9-arquitetural-n%C3%A3o-tecnol%C3%B3gica-144381955268?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/144381955268</guid>
            <category><![CDATA[message-broker]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <category><![CDATA[brokerless]]></category>
            <category><![CDATA[apache-kafka]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Wed, 21 Oct 2026 19:08:56 GMT</pubDate>
            <atom:updated>2026-10-21T19:08:56.820Z</atom:updated>
            <content:encoded><![CDATA[<p>Ao discutir comunicação entre componentes, é comum a conversa começar pela tecnologia: <strong>Kafka, RabbitMQ, NATS</strong>, filas gerenciadas ou bibliotecas <strong>brokerless</strong>. Essa abordagem inverte a ordem da decisão. Antes de selecionar um produto, precisamos entender qual problema de comunicação existe, quais garantias o sistema precisa oferecer e quais consequências estamos dispostos a assumir.</p><p><strong>Message brokers</strong>, <strong>event brokers</strong> e comunicação <strong>brokerless</strong> não são apenas opções de implementação equivalentes. Cada abordagem estabelece um modelo diferente para desacoplamento, persistência, entrega, recuperação e operação. A arquitetura deve orientar a escolha a partir dos direcionadores de negócio e dos atributos de qualidade, não da popularidade de uma tecnologia.</p><h3>O problema arquitetural vem antes do broker</h3><p>A comunicação entre componentes pode representar uma solicitação que precisa de resposta, uma tarefa a ser executada, uma notificação de que algo aconteceu ou um fluxo contínuo de eventos que vários consumidores precisam processar. Embora essas interações possam usar mecanismos semelhantes, suas necessidades são diferentes.</p><p>Uma operação que exige resposta imediata pode ser mais simples com uma API síncrona. Uma tarefa demorada pode se beneficiar de uma fila, permitindo que o produtor conclua sua solicitação sem aguardar o processamento. Já um domínio que precisa distribuir mudanças para vários sistemas independentes pode exigir publicação de eventos, retenção e capacidade de reprocessamento.</p><p>Por isso, a primeira etapa é explicitar os direcionadores arquiteturais: latência aceitável, volume e variabilidade da carga, tolerância à perda de mensagens, necessidade de ordenação, quantidade de consumidores, retenção histórica, recuperação após falhas, segurança e custo operacional. Sem esses critérios, a escolha tende a se apoiar em preferência ou tendência.</p><h3>Message brokers: coordenar a entrega de mensagens</h3><p>O message broker tradicional atua como intermediário entre produtores e consumidores. Ele recebe mensagens e as encaminha conforme filas, tópicos, assinaturas e regras de entrega. Tecnologias como RabbitMQ e IBM MQ são exemplos conhecidos desse modelo, embora os recursos e as garantias variem conforme o produto e sua configuração.</p><p>Esse modelo é útil quando o objetivo é distribuir trabalho, desacoplar temporalmente os participantes e controlar a entrega. Uma fila pode permitir que vários workers dividam o processamento; confirmações e redelivery ajudam a recuperar mensagens não concluídas; e limites de concorrência ou de tamanho de fila podem contribuir para controlar a pressão sobre os consumidores.</p><p>O broker, porém, não elimina a complexidade: ele a desloca e a torna explícita. É necessário definir o que acontece com mensagens não confirmadas, quantas tentativas serão realizadas, como tratar mensagens venenosas, se a ordem importa e como evitar efeitos duplicados. “Entrega pelo menos uma vez” não significa que o efeito de negócio ocorrerá uma única vez; consumidores idempotentes e estratégias de deduplicação continuam relevantes.</p><h3>Event brokers: eventos como fluxo durável</h3><p>Um event broker é orientado à distribuição de eventos que representam fatos ocorridos. Em plataformas de event streaming, como Apache Kafka, os eventos são organizados em streams ou tópicos e mantidos por um período definido, em vez de necessariamente desaparecerem após o consumo. Produtores e grupos de consumidores podem evoluir de forma independente, e diferentes aplicações podem ler o mesmo histórico conforme suas necessidades.</p><p>A retenção durável permite recuperar consumidores, reconstruir projeções, integrar novos sistemas e reprocessar dados. Esse modelo pode ser especialmente útil em arquiteturas orientadas a eventos, integração entre domínios, captura de mudanças de dados (CDC), pipelines analíticos e cenários em que múltiplos consumidores precisam interpretar os mesmos fatos.</p><p>A diferença não está apenas no nome do produto. Um event streaming platform introduz decisões sobre particionamento, chaves, ordenação por partição, retenção, compatibilidade de esquemas, evolução de contratos e lag dos consumidores. A capacidade de replay é valiosa, mas exige que os efeitos do reprocessamento sejam controlados. Também não se deve presumir que todos os consumidores receberão eventos exatamente na mesma ordem global: as garantias dependem do modelo e da configuração.</p><p>A Confluent, empresa que desenvolve uma plataforma comercial baseada em Apache Kafka, descreve o event broker como uma camada distribuída que desacopla fontes e consumidores, com armazenamento durável e leitura independente dos streams. Essa visão reforça um ponto arquitetural: o broker não é apenas um canal de transporte; ele pode fazer parte da estratégia de dados e integração do sistema.</p><h3>Brokerless: remover o intermediário também é uma decisão</h3><p>Na comunicação brokerless, produtores e consumidores se comunicam diretamente, ou por meio de uma biblioteca de mensagens que não depende de um serviço broker centralizado. Bibliotecas como ZeroMQ oferecem padrões de comunicação entre processos sem exigir, por definição, uma infraestrutura intermediária persistente. Webhooks, conexões diretas e alguns mecanismos de multicast também podem se encaixar em desenhos sem broker dedicado.</p><p>A ausência do broker pode reduzir saltos de rede, latência, infraestrutura e esforço operacional. Em cenários controlados, com participantes conhecidos, baixa latência prioritária e tolerância explícita a falhas, esse desenho pode ser adequado. Mas remover o intermediário não remove as responsabilidades que ele ajudava a concentrar.</p><p>Sem uma camada durável compartilhada, a aplicação precisa considerar o que ocorre quando o consumidor está indisponível, quando o produtor falha antes de reenviar uma mensagem ou quando a rede interrompe a comunicação. Retentativas, buffering, descoberta de participantes, backpressure, observabilidade e recuperação podem passar a ser responsabilidades distribuídas entre os próprios componentes. O resultado pode ser eficiente, mas também pode aumentar o acoplamento operacional e a complexidade do código.</p><h3>Comparar pelos trade-offs, não por slogans</h3><p>Não existe uma abordagem universalmente superior. Um message broker tradicional pode simplificar a distribuição de tarefas e a gestão da entrega. Um event broker pode oferecer histórico durável, retenção de eventos e múltiplos consumidores independentes. Já uma solução brokerless pode reduzir a latência e a infraestrutura em interações específicas, desde que os requisitos de confiabilidade sejam compatíveis com esse modelo.</p><p>A diferença está nas responsabilidades assumidas por cada abordagem. No message broker, é necessário considerar o comportamento de redelivery, a possibilidade de mensagens duplicadas e o acúmulo de filas. No event broker, a decisão envolve aspectos como particionamento, compatibilidade dos contratos, política de retenção, atraso dos consumidores (consumer lag) e capacidade de reprocessamento. No modelo brokerless, a aplicação pode precisar implementar mecanismos de retentativa, buffering, descoberta de participantes, controle de pressão (backpressure) e recuperação após falhas.</p><p>A escolha deve considerar a intenção da comunicação, as garantias necessárias e o custo operacional. Filas podem ser adequadas para tarefas assíncronas e distribuição de trabalho. Streams de eventos fazem sentido quando há necessidade de histórico, reprocessamento e consumo independente por diferentes sistemas. A comunicação direta pode ser suficiente em cenários controlados, nos quais a baixa latência é prioritária e as limitações de disponibilidade e entrega são conhecidas.</p><p>Portanto, a decisão arquitetural não deve partir de slogans como “event-driven é melhor”, “brokerless é mais rápido” ou “Kafka resolve integração”. Deve partir dos direcionadores de negócio, dos atributos de qualidade e dos trade-offs que a solução precisa assumir. O objetivo é selecionar o modelo de comunicação que atenda aos requisitos com a menor complexidade sustentável, sem introduzir capacidades desnecessárias nem comprometer as garantias essenciais do sistema.</p><h3>Como conduzir a decisão arquitetural</h3><p>Uma decisão consistente começa pelo contexto e termina em validação. Primeiro, descreva a interação: é uma solicitação, uma tarefa ou um fato de negócio? Depois, estabeleça as garantias necessárias: podemos perder mensagens? Precisamos de ordenação? O consumidor pode ficar indisponível por quanto tempo? Precisamos reprocessar o histórico?</p><p>Em seguida, compare alternativas viáveis usando critérios observáveis. Avalie latência e throughput sob carga realista, comportamento em falhas, custo de infraestrutura, esforço de operação, segurança, governança de contratos e capacidade da equipe. Registre os trade-offs aceitos e defina como a decisão será validada por testes, métricas e observabilidade em produção.</p><p>Também é importante evitar a adoção de um broker como resposta automática à existência de microsserviços. Uma API síncrona pode ser a opção mais clara quando uma resposta imediata é parte do contrato. Uma fila pode bastar para tarefas. Um stream durável faz sentido quando retenção, replay e múltiplos consumidores são requisitos reais. Em sistemas menores, uma solução mais simples pode reduzir custo e pontos de falha — desde que cumpra as garantias necessárias.</p><h3>Considerações finais</h3><p><strong>Message brokers, event brokers e brokerless</strong> representam diferentes formas de organizar a comunicação e distribuir responsabilidades em sistemas de software. A decisão influencia não apenas desempenho, mas também confiabilidade, recuperação, evolução dos contratos, observabilidade e custo operacional.</p><p>O papel da arquitetura não é escolher a tecnologia mais conhecida nem eliminar todos os <strong>trade-offs</strong>. É tornar explícito o problema que precisa ser resolvido, comparar alternativas coerentes com os direcionadores e validar as consequências da escolha. A melhor solução é aquela que entrega as garantias necessárias com a menor complexidade sustentável — e que pode evoluir quando o contexto mudar mantendo o menor custo da mudança.</p><h3>Referências para aprofundamento</h3><p><strong>Confluent Developer — Event Broker<br></strong>https://developer.confluent.io/patterns/event-stream/event-broker/</p><p><strong>Confluent — Architectural Decision Guide: When to Use Apache Kafka (And When You Shouldn’t)<br></strong>https://preprod.www.confluent.io/blog/architectural-decision-guide-when-to-use-apache-kafka-and-when-you-shouldnt/</p><p><strong>Martin Kleppmann — Designing Data-Intensive Applications<br></strong>https://dataintensive.net/</p><p><strong>ZeroMQ Guide<br></strong>https://zguide.zeromq.org/</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=144381955268" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sistemas distribuídos: a Arquitetura começa quando a falha deixa de ser uma exceção]]></title>
            <link>https://medium.com/@marcelomg21/sistemas-distribu%C3%ADdos-a-arquitetura-come%C3%A7a-quando-a-falha-deixa-de-ser-uma-exce%C3%A7%C3%A3o-3547bf511055?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/3547bf511055</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[computação-distribuída]]></category>
            <category><![CDATA[distributed-systems]]></category>
            <category><![CDATA[fault-tolerance]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Wed, 21 Oct 2026 18:45:54 GMT</pubDate>
            <atom:updated>2026-10-21T18:45:54.646Z</atom:updated>
            <content:encoded><![CDATA[<p>De <strong>Joe Armstrong</strong> às arquiteturas modernas, por que tolerar falhas é mais importante do que tentar evitá-las? Por muito tempo, parte da engenharia de software foi guiada por uma expectativa confortável. Se projetarmos corretamente, testarmos o suficiente e mantivermos a infraestrutura estável, o sistema deverá funcionar. Essa expectativa perde força quando o software depende de redes, serviços remotos, bancos de dados, filas, regiões de nuvem e componentes que evoluem de forma independente.</p><p>Em um sistema distribuído, a falha não precisa derrubar tudo para comprometer o resultado. Uma requisição pode chegar ao destino e a resposta se perder. Um serviço pode continuar funcionando enquanto outro está indisponível. Dois componentes podem enxergar estados diferentes do mesmo negócio. O desafio não é apenas detectar que algo falhou, mas decidir o que fazer enquanto não sabemos exatamente o que aconteceu.</p><p>A contribuição de Joe Armstrong e da experiência acumulada em Erlang ajuda a mudar a pergunta. Em vez de tentar construir componentes que nunca falham, devemos construir sistemas capazes de continuar operando, recuperar-se e limitar o impacto quando uma parte falha.</p><h3>A falha faz parte do modelo, não é um acidente</h3><p>Em sistemas distribuídos, não existe uma visão perfeita e instantânea de tudo o que acontece. A rede pode atrasar ou perder mensagens. Um timeout não prova que o serviço remoto morreu. Ele prova apenas que a resposta não chegou dentro do prazo esperado. O serviço pode ter processado a operação, mas a resposta pode ter se perdido no caminho.</p><p>Essa incerteza muda decisões simples. Se um cliente repetir uma cobrança depois de um timeout, poderá cobrar duas vezes. Se não repetir, talvez a operação nunca aconteça. A solução não é escolher cegamente entre repetir ou desistir. É projetar a operação com identidade, idempotência, estado observável e regras claras de recuperação.</p><p>A arquitetura precisa assumir falhas parciais. Um sistema pode estar saudável em alguns pontos e degradado em outros. A pergunta não é somente ‘o sistema está no ar?’. É também ‘quais capacidades continuam disponíveis, quais estão degradadas e quais consequências isso produz para o negócio?’</p><h3>O que Joe Armstrong nos ensinou</h3><p><strong>Joe Armstrong</strong>, um dos criadores de <strong>Erlang (BEAM VM)</strong>, trabalhou com sistemas que precisavam permanecer disponíveis por longos períodos, mesmo diante de defeitos de software e falhas operacionais. A filosofia associada a Erlang valoriza processos leves, isolamento, troca de mensagens e supervisão. Cada processo mantém seu próprio estado e interage com outros por mensagens, em vez de depender de memória compartilhada como mecanismo central de coordenação.</p><p>O isolamento reduz a possibilidade de uma falha local corromper diretamente o estado de outros componentes. A supervisão acrescenta uma estratégia explícita de recuperação. Processos supervisores monitoram trabalhadores e podem reiniciá-los quando necessário, organizando essa responsabilidade em árvores de supervisão.</p><p>A expressão frequentemente associada a essa escola de pensamento, ‘let it crash’, não significa ignorar erros nem aceitar indisponibilidade sem controle. Significa reconhecer que tentar prever e corrigir todo estado inválido dentro de um componente pode ser mais arriscado do que encerrar sua execução, preservar o isolamento e permitir que um mecanismo conhecido o reinicie.</p><p>Reiniciar um processo não resolve qualquer falha. Se o defeito estiver nos dados persistidos, numa dependência indisponível ou numa configuração incorreta, o reinício pode apenas repetir o problema. Tolerância a falhas exige combinar isolamento com limites de reinício, observabilidade, recuperação de estado e tratamento de falhas persistentes.</p><h3>Tolerância a falhas é uma propriedade do sistema</h3><p>Um componente pode ser resiliente sem que o sistema inteiro seja. Um serviço pode reiniciar rapidamente, mas se todas as requisições dependem de um banco único, esse banco continua sendo um ponto crítico. Um cluster pode ter várias réplicas, mas se todas estiverem na mesma zona de disponibilidade, um único incidente poderá afetá-las simultaneamente.</p><p>Tolerância a falhas não é uma biblioteca, uma configuração de Kubernetes ou uma caixa marcada num diagrama. É uma propriedade que emerge de decisões sobre aplicação, dados, infraestrutura, comunicação, operação e negócio. Algumas práticas ajudam a transformar esse princípio em mecanismos concretos:</p><ul><li>Isolamento de falhas. Limitar o alcance de uma falha por meio de processos, serviços, pools de recursos, zonas e limites de concorrência.</li><li>Timeouts e limites de recursos. Impedir que chamadas lentas consumam indefinidamente conexões, threads, memória ou capacidade.</li><li>Retries com backoff e jitter. Repetir operações transitórias de forma controlada, evitando que clientes agravem uma indisponibilidade.</li><li>Circuit breakers e bulkheads. Interromper chamadas a dependências degradadas e impedir que um domínio consuma todos os recursos compartilhados.</li><li>Redundância e failover. Manter alternativas de execução sem ignorar falhas correlacionadas ou dados divergentes.</li><li>Observabilidade. Correlacionar logs, métricas e traces para compreender sintomas, dependências e impacto sobre o usuário.</li><li>Recuperação testada. Validar restauração de dados, failover e retomada de consumidores, em vez de presumir que funcionarão.</li></ul><h3>Arquiteturas modernas e seus compromissos</h3><p>Microsserviços, mensageria, replicação e plataformas de nuvem oferecem ferramentas para distribuir carga e limitar falhas. Nenhuma delas elimina a complexidade. Cada mecanismo resolve certos problemas e introduz outros.</p><p>Microsserviços podem isolar implantação e escala, mas aumentam a quantidade de chamadas remotas e os pontos de falha. Mensageria desacopla produtores e consumidores no tempo, mas exige lidar com duplicidade, ordenação, mensagens atrasadas e filas acumuladas. Replicação melhora a disponibilidade de leitura ou a recuperação, mas torna mais difícil decidir qual estado deve prevalecer após uma partição ou atualização concorrente.</p><p>A consistência eventual pode ser adequada quando o negócio tolera que diferentes visões sejam atualizadas em momentos distintos. Já operações como transferências financeiras, controle de saldo ou reserva de estoque podem exigir invariantes mais fortes. O desenho deve partir do significado do dado e das consequências de uma divergência, não da preferência por uma tecnologia.</p><p>Uma arquitetura resiliente precisa tornar explícitas algumas perguntas:</p><ul><li>O que o sistema deve continuar fazendo quando uma dependência falha?</li><li>Quais operações podem ser repetidas com segurança e quais exigem idempotência?</li><li>Que inconsistências temporárias o negócio aceita e por quanto tempo?</li><li>Qual é o limite de degradação aceitável antes de rejeitar novas solicitações?</li><li>Como conter e recuperar uma falha sem criar outra durante a recuperação?</li></ul><h3>Um exemplo prático: compra, pagamento e estoque</h3><p>Imagine uma compra online que depende de três capacidades: registrar o pedido, confirmar o pagamento e reservar o estoque. Uma implementação síncrona e fortemente encadeada pode fazer o cliente esperar por todas as dependências. Se o serviço de estoque estiver lento, o tempo de resposta do fluxo inteiro aumenta. Se o pagamento for processado, mas a resposta se perder, o sistema precisa saber se deve consultar o resultado ou repetir a operação.</p><p>Uma arquitetura orientada a eventos pode registrar o pedido e publicar um evento para os próximos passos. Isso reduz o acoplamento temporal, mas não torna o fluxo automaticamente correto. O evento pode ser entregue mais de uma vez. Um consumidor pode falhar depois de atualizar o estoque e antes de confirmar o processamento. A mensagem pode ficar retida enquanto uma dependência está indisponível.</p><p>O desenho pode combinar padrões. Uma outbox transacional coordena a persistência do estado com a publicação do evento. Consumidores idempotentes reconhecem mensagens já processadas. Uma saga define ações compensatórias quando uma sequência de passos não chega ao resultado esperado. Métricas e alertas revelam filas crescentes antes que o atraso se transforme em incidente.</p><p>O valor não está em aplicar todos os padrões. Está em identificar onde a falha pode ocorrer, qual invariante precisa ser preservada e qual mecanismo reduz o risco com complexidade aceitável.</p><h3>A arquitetura deve desenhar a recuperação</h3><p>É comum dedicar muito tempo ao caminho feliz, aquele em que todas as dependências respondem e cada etapa termina como esperado. Sistemas distribuídos exigem desenhar também os caminhos de falha. O que acontece quando a resposta atrasa? Quando uma mensagem chega duas vezes? Quando o processo cai depois de gravar o dado? Quando a região primária fica indisponível? Quando a recuperação sobrecarrega um serviço que já está degradado?</p><p>Essa visão aproxima arquitetura e operação. SLOs e orçamentos de erro ajudam a explicitar quanto de indisponibilidade ou degradação é aceitável. Testes de resiliência verificam hipóteses sobre falhas. Deploys graduais e rollback reduzem o impacto de mudanças. Runbooks, backups restauráveis e exercícios de recuperação transformam documentação em capacidade real.</p><p>Também é preciso reconhecer o custo. Redundância aumenta infraestrutura e operação. Replicação pode ampliar divergências. Retentativas podem criar tempestades de tráfego. Mais serviços podem melhorar o isolamento e, ao mesmo tempo, aumentar o número de dependências. Não existe arquitetura que maximize simultaneamente disponibilidade, consistência, desempenho, simplicidade e custo.</p><p>O papel do arquiteto não é prometer ausência de falhas. É tornar os riscos visíveis, definir prioridades com o negócio, registrar os compromissos assumidos e verificar se os mecanismos escolhidos realmente produzem o comportamento esperado.</p><h3>Considerações finais</h3><p>A principal lição que podemos extrair de Joe Armstrong é menos sobre uma linguagem de programação e mais sobre uma maneira de pensar. Sistemas complexos não se tornam confiáveis porque cada componente foi declarado confiável. Eles se tornam mais confiáveis quando falhas locais são esperadas, isoladas, observadas e tratadas por mecanismos que não dependem de improvisação.</p><p>Arquiteturas modernas oferecem mais recursos do que nunca para distribuir processamento, replicar dados, automatizar recuperação e observar o comportamento em produção. Mas ferramentas não substituem o entendimento dos limites do sistema. Uma arquitetura distribuída mal compreendida apenas distribui a complexidade e torna seus efeitos mais difíceis de rastrear.</p><p>A maturidade arquitetural aparece quando deixamos de perguntar apenas como construir o caminho ideal e passamos a perguntar como preservar o que importa quando as condições deixam de ser ideais. A falha deixa de ser um evento inesperado e passa a fazer parte do modelo de projeto.</p><p>No fim, tolerância a falhas é uma forma de humildade da engenharia. É reconhecer que não controlamos todas as condições de execução, mas podemos decidir como o sistema reage a elas. Não podemos garantir que cada parte permanecerá saudável. Podemos, porém, projetar para que uma parte doente não condene todas as outras.</p><h3>Referências essenciais</h3><ul><li><strong>Erlang/OTP Documentation — Design Principles — </strong><a href="https://www.erlang.org/docs/27/system/design_principles.html">www.erlang.org/docs/27/system/design_principles.html</a></li><li><strong>Erlang/OTP Documentation — Supervisor Behaviour — </strong><a href="https://www.erlang.org/doc/system/sup_princ.html">www.erlang.org/doc/system/sup_princ.html</a></li><li><strong>Martin Kleppmann, Designing Data-Intensive Applications — </strong><a href="https://dataintensive.net/">dataintensive.net/</a></li><li><strong>Martin Kleppmann, Online Event Processing — </strong><a href="https://martin.kleppmann.com/2019/05/01/olep-cacm.html">martin.kleppmann.com/2019/05/01/olep-cacm.html</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3547bf511055" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Agentes de IA não eliminam a arquitetura.
Eles tornam-na mais crítica]]></title>
            <link>https://medium.com/@marcelomg21/agentes-de-ia-n%C3%A3o-eliminam-a-arquitetura-eles-tornam-na-mais-cr%C3%ADtica-fa94a2119b0a?source=rss-56cdc11c288------2</link>
            <guid isPermaLink="false">https://medium.com/p/fa94a2119b0a</guid>
            <category><![CDATA[architectural-design]]></category>
            <category><![CDATA[agentes-de-ia]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[arquitetura-de-software]]></category>
            <dc:creator><![CDATA[Marcelo M. Gonçalves]]></dc:creator>
            <pubDate>Wed, 21 Oct 2026 12:54:31 GMT</pubDate>
            <atom:updated>2026-10-21T12:54:31.177Z</atom:updated>
            <content:encoded><![CDATA[<p>A tendência mais provável é que a inteligência artificial não elimine a arquitetura de software, mas transforme a forma como ela é praticada. Com agentes capazes de analisar repositórios, propor mudanças, gerar código, executar testes e interagir com ferramentas, uma parte crescente do trabalho de engenharia pode ser automatizada. Isso não significa, porém, que as decisões estruturais deixem de existir. Pelo contrário: quanto mais rápido conseguimos implementar uma solução, mais importante se torna garantir que estamos construindo a solução certa.</p><p>O risco não está apenas em a IA produzir código incorreto. Está em produzir código plausível, funcional e coerente localmente, mas incompatível com os objetivos do negócio, com os requisitos de qualidade ou com a direção arquitetural do sistema. A velocidade de execução aumenta; a responsabilidade por definir limites, prioridades e consequências continua sendo humana e organizacional.</p><h3>O que os agentes de IA realmente mudam?</h3><p>Agentes de IA vão além de responder perguntas ou completar trechos de código. Quando conectados a ferramentas, contexto e permissões, podem decompor tarefas, inspecionar código, alterar múltiplos arquivos, executar comandos e avaliar resultados. Isso desloca a discussão de “a IA escreve código?” para “quais atividades podemos delegar, sob quais limites e com qual nível de confiança?”.</p><p>Tarefas repetitivas, mudanças localizadas, criação de testes, documentação técnica e exploração de alternativas tendem a ser bons candidatos à automação. Já decisões que envolvem ambiguidade de negócio, impactos entre domínios, riscos operacionais, segurança, custos e compromissos de longo prazo exigem contexto e julgamento. A fronteira não é fixa: ela depende da maturidade das ferramentas, da criticidade do sistema e da qualidade dos controles disponíveis.</p><h3>Três estágios de automação</h3><p>A evolução pode ser entendida em três estágios. Na IA assistiva, a ferramenta sugere código, explica alternativas e apoia a análise, enquanto a pessoa conduz a tarefa e valida o resultado. Na IA executora, recebe um objetivo delimitado, altera artefatos, executa testes e apresenta evidências para revisão. Na autonomia delimitada, opera em um espaço controlado, com permissões, políticas, critérios de aceitação, observabilidade e possibilidade de reversão.</p><p>A evolução entre esses estágios não deve ser tratada como uma corrida para remover pessoas do processo. É uma decisão de engenharia. Quanto maior a autonomia concedida, maior precisa ser a clareza sobre o escopo, os dados acessíveis, as ações permitidas, os limites de custo e os mecanismos de contenção. Autonomia sem governança apenas acelera a propagação de erros.</p><h3>A arquitetura torna-se mais importante</h3><p>Uma arquitetura explícita ajuda pessoas e agentes a entenderem como o sistema deve evoluir. Limites de módulos, contratos, ownership dos dados, regras de dependência, padrões de segurança e requisitos de operação reduzem o espaço de interpretações possíveis. Sem esse contexto, um agente pode otimizar a tarefa imediata e, ao mesmo tempo, aumentar o acoplamento, duplicar regras de negócio ou criar caminhos alternativos que comprometem a consistência do sistema.</p><p>Isso não significa que toda decisão deva virar um documento extenso ou que a arquitetura precise ser centralizada. O objetivo é tornar as decisões relevantes acessíveis, testáveis e evolutivas. ADRs, catálogos de componentes, contratos versionados, políticas automatizadas, testes de arquitetura e fitness functions podem transformar princípios arquiteturais em restrições verificáveis no fluxo de desenvolvimento.</p><p>A arquitetura também precisa ser avaliada no nível do sistema. Uma alteração pode passar nos testes unitários e ainda degradar a latência de uma jornada crítica, ampliar privilégios, aumentar o custo de infraestrutura ou enfraquecer a resiliência. Por isso, a validação deve combinar testes, métricas, análise de dependências, observabilidade e revisão proporcional ao risco.</p><h3>O papel do arquiteto em um fluxo orientado por agentes</h3><p>O valor do arquiteto não está em competir com a IA na produção de código. Está em orientar o trabalho para que a automação gere valor sustentável. Isso começa antes da implementação: compreender os direcionadores de negócio, traduzi-los em direcionadores arquiteturais, explicitar restrições e comparar alternativas que atendam às características de qualidade prioritárias.</p><p>Na prática, esse trabalho envolve:</p><ul><li>Definir objetivos e critérios de aceitação claros, incluindo requisitos não funcionais mensuráveis.</li><li>Estabelecer limites de contexto, contratos, permissões e políticas para os agentes.</li><li>Avaliar alternativas e explicitar trade-offs entre desempenho, disponibilidade, segurança, custo e modificabilidade.</li><li>Determinar quais mudanças exigem revisão humana e quais podem seguir por um caminho automatizado.</li><li>Garantir evidências de validação: testes, benchmarks, análise de segurança, métricas e mecanismos de rollback.</li><li>Revisar os resultados no contexto do sistema, e não apenas como alterações isoladas no código.</li></ul><p>O arquiteto também precisa aproximar-se ainda mais da engenharia. Diretrizes que não podem ser verificadas ou que não refletem a realidade das equipes tendem a ser ignoradas — por pessoas ou por agentes. A arquitetura deve ser suficientemente clara para orientar decisões e suficientemente flexível para evoluir quando novas evidências surgirem.</p><h3>Trade-offs não desaparecem com a IA</h3><p>Agentes podem ajudar a listar opções, estimar impactos e executar experimentos. Ainda assim, não existe uma solução que maximize simultaneamente todas as características de qualidade. Aumentar a redundância pode elevar a disponibilidade, mas também o custo e a complexidade operacional. Reduzir chamadas remotas pode melhorar a latência, mas aumentar o acoplamento. Restringir permissões fortalece a segurança, mas pode limitar determinadas formas de automação.</p><p>É nesse ponto que um framework de trade-offs ganha relevância. Para cada decisão importante, devemos registrar o contexto, o direcionador que motivou a mudança, as alternativas consideradas, os ganhos e perdas esperados, as consequências aceitas e a forma de validação. A IA pode acelerar a análise e reunir evidências; a organização precisa assumir a decisão e seus efeitos.</p><h3>Competências que ganham relevância</h3><p>A adoção de agentes reduz o valor relativo de algumas atividades manuais, mas aumenta a importância de competências que permitem direcionar, avaliar e controlar o resultado. Entre elas estão a compreensão do negócio, o pensamento sistêmico, a análise de riscos, a segurança, a observabilidade, a capacidade de formular bons critérios de aceitação e a comunicação de decisões técnicas.</p><p>Também será necessário saber trabalhar com automação de forma crítica: verificar pressupostos, identificar lacunas de contexto, avaliar evidências e reconhecer quando uma resposta aparentemente convincente não é suficiente. A produtividade não deve ser medida apenas por linhas de código ou velocidade de entrega, mas pelo valor produzido, pela qualidade operacional e pelo custo de manter e evoluir a solução.</p><h3>Considerações finais</h3><p>Agentes de IA não tornam a arquitetura dispensável. Eles ampliam a capacidade de implementar mudanças e, por isso, tornam mais críticas as decisões que orientam essas mudanças. Quando a execução fica mais barata e rápida, erros estruturais também podem ser introduzidos e disseminados com maior velocidade.</p><p>A resposta não é tentar controlar cada linha de código nem confiar cegamente na autonomia dos agentes. É construir um ambiente em que objetivos, limites e decisões arquiteturais sejam claros; em que políticas possam ser verificadas automaticamente; e em que resultados sejam avaliados por evidências. A arquitetura deixa de ser apenas uma atividade de desenho e passa a ser uma capacidade contínua de direcionamento, validação e evolução.</p><p>A IA pode substituir partes do trabalho do arquiteto. Não elimina a necessidade de compreender o problema, escolher entre alternativas imperfeitas e assumir os trade-offs. Quanto maior a capacidade de execução dos agentes, maior a importância de saber para onde o sistema deve evoluir e principalmente por quê.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fa94a2119b0a" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>