Introdução
Em 1994, quatro pesquisadores da computação — Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides — publicaram um livro que mudaria para sempre a forma como engenheiros de software pensam sobre seus problemas. “Design Patterns: Elements of Reusable Object-Oriented Software” catalogou 23 soluções recorrentes para problemas recorrentes no desenvolvimento orientado a objetos. A comunidade os apelidou de Gang of Four (GoF) — a Gangue dos Quatro.
Três décadas depois, em um mundo de cloud pública, arquiteturas híbridas, Kubernetes, serverless, times distribuídos globalmente e microserviços que se comunicam por eventos, esses mesmos padrões continuam sendo referência. Não porque o mundo parou. Porque os problemas fundamentais de software não mudaram — apenas a escala e o ambiente em que eles aparecem mudaram.
Este artigo explora:
- Por que precisamos de arquitetura de software — e o que acontece quando ignoramos
- A origem e o propósito do GoF — contexto histórico, motivações e a estrutura dos 23 padrões
- Como os padrões se aplicam independentemente da linguagem — GoF não é Java, nem C++, é uma linguagem de design
- A revolução da cloud e dos microserviços — como os padrões clássicos evoluíram e quais novos surgiram
- Times de desenvolvimento e sustentação — por que a arquitetura é o elo que mantém sistemas vivos por mais de uma geração de desenvolvedores
Para quem é este artigo: desenvolvedores com experiência prática que querem elevar seu raciocínio de solução de problemas para o nível de arquitetura de software.
📦 Código-fonte: A implementação completa deste artigo está no repositório blog-zocateli-sample no GitHub. Clone, explore e adapte ao seu contexto.
Por Que Arquitetura de Software Importa
Software sem arquitetura: o custo invisível
Imagine um sistema bancário construído por 50 desenvolvedores ao longo de 8 anos, sem nenhuma convenção arquitetural. Cada desenvolvedor resolveu os problemas do seu jeito. O resultado é o que a industria chama de Big Ball of Mud — uma massa amorfa onde qualquer mudança pode quebrar algo em qualquer lugar.
Esse não é um cenário hipotético. É o estado natural de sistemas que crescem sem intenção arquitetural. Os sintomas são reconhecíveis:
- Acoplamento invisível: alterar o módulo de pagamentos quebra o módulo de relatórios, e ninguém sabe por quê
- Conhecimento tribal: apenas 2 desenvolvedores sabem como aquela parte “funciona de verdade”
- Medo de deploy: “sexta não sobe” virou cultura porque ninguém tem confiança no sistema
- Regressão constante: cada nova funcionalidade parece trazer 3 bugs antigos de volta
- Onboarding demorado: um desenvolvedor novo leva 6 meses para ser produtivo
Arquitetura não é o que você faz antes de escrever código — é a intenção que guia cada decisão de design ao longo de toda a vida do sistema.
O que é arquitetura de software, afinal?
Martin Fowler define arquitetura de software como “as decisões importantes e difíceis de reverter” em um sistema. Ralph Johnson a define como “as decisões compartilhadas pelos desenvolvedores sobre como organizar o sistema”.
Essas definições revelam duas dimensões da arquitetura:
- Técnica: modularidade, acoplamento, coesão, contratos entre componentes, fluxo de dados, tratamento de falhas
- Social: vocabulário comum entre pessoas, convenções que permitem que um time de 20 trabalhhe com consistência
A segunda dimensão é frequentemente ignorada — e é justamente onde os padrões GoF brilham.
O custo do débito técnico arquitetural
O débito técnico arquitetural é diferente e mais grave que o débito técnico de código. Refatorar um método é uma tarde. Mudar a arquitetura de um sistema em produção pode levar meses, com alto risco. Por isso, decisões arquiteturais erradas compõem juros rápidos:
| |
Arquitetura não elimina o débito técnico — mas o direciona e o torna visível e gerenciável.
A Origem do Gang of Four
O contexto histórico: a crise do software orientado a objetos
Em 1994, a programação orientada a objetos tinha vivido seu auge de hype. C++, Smalltalk, e mais recentemente Java prometiam que herança, encapsulamento e polimorfismo resolveriam todos os problemas de reutilização de código. A promessa não se cumpriu sozinha.
O problema não era a orientação a objetos em si — era que desenvolvedores não tinham um vocabulário compartilhado para expressar como usar as ferramentas da OO. Cada projeto reinventava as mesmas soluções para os mesmos problemas. Um desenvolvedor experiente em Smalltalk tinha soluções consolidadas para “como desacoplar um algoritmo de suas implementações concretas” — mas essas soluções viviam em sua cabeça, não em livros.
Gamma, Helm, Johnson e Vlissides perceberam que estavam, independentemente, chegando às mesmas soluções para os mesmos tipos de problema. A ideia do livro nasceu de uma conferência OOPSLA em 1990, quando Erich Gamma e Richard Helm trocaram notas sobre padrões recorrentes. O processo de escrita durou 4 anos.
A influência de Christopher Alexander
Os autores se inspiraram explicitamente em Christopher Alexander, um arquiteto (de construções físicas, não de software) que em 1977 publicou “A Pattern Language” — um catálogo de 253 padrões recorrentes em arquitetura urbana e de edificações, desde o design de cidades até o posicionamento de janelas.
A ideia central de Alexander: problemas recorrentes em um contexto têm soluções recorrentes que podem ser nomeadas, documentadas e comunicadas. Quando um arquiteto diz “esta sala precisa de um pé-direito duplo”, todos os outros arquitetos sabem exatamente o que isso significa — sem precisar explicar do zero.
GoF aplicou essa ideia ao software: ao dizer “use um Strategy aqui”, você comunica uma estrutura inteira de design em uma única palavra.
A estrutura de um padrão GoF
Cada um dos 23 padrões segue um formato consistente:
| Campo | Descrição |
|---|---|
| Nome | O vocabulário — “Strategy”, “Factory”, “Observer” |
| Intenção | O que o padrão faz, em uma frase |
| Também Conhecido Como | Nomes alternativos |
| Motivação | Cenário concreto que justifica o padrão |
| Aplicabilidade | Quando usar |
| Estrutura | Diagrama de classes (UML) |
| Participantes | As classes e suas responsabilidades |
| Colaborações | Como os participantes interagem |
| Consequências | Trade-offs — o que você ganha e o que você abre mão |
| Implementação | Notas de implementação, variações |
| Exemplo de Código | C++ no livro original |
| Padrões Relacionados | Conexões com outros padrões |
O campo Consequências é o mais ignorado e o mais valioso. Todo padrão tem um custo. Conhecer o custo é o que diferencia um arquiteto de alguém que apenas aplica padrões mecanicamente.
Os 23 Padrões GoF
Os 23 padrões são divididos em três categorias, baseadas no tipo de problema que resolvem:
Padrões Criacionais — Como os Objetos São Criados
Encapsulam e abstraem o processo de criação de objetos. O objetivo é desacoplar o código que usa um objeto do código que o instancia.
Factory Method
Define uma interface para criar um objeto, mas deixa as subclasses decidirem qual classe instanciar.
| |
Abstract Factory
Cria famílias de objetos relacionados sem especificar suas classes concretas.
| |
Builder
Separa a construção de um objeto complexo de sua representação.
| |
Prototype
Cria novos objetos copiando (clonando) um objeto existente.
| |
Singleton
Garante que uma classe tenha apenas uma instância e provê acesso global a ela.
| |
Padrões Estruturais — Como os Objetos São Compostos
Tratam da composição de classes e objetos para formar estruturas maiores, mantendo flexibilidade e eficiência.
Adapter
Converte a interface de uma classe em outra interface esperada pelos clientes.
| |
Decorator
Adiciona responsabilidades a um objeto dinamicamente, sem alterar sua classe.
| |
Facade
Provê uma interface simplificada para um subsistema complexo.
| |
Proxy
Provê um substituto para outro objeto para controlar o acesso a ele.
| |
Composite, Bridge, Flyweight
Os demais padrões estruturais resolvem problemas igualmente comuns:
- Composite — trata objetos individuais e coleções de forma uniforme (árvores de menus, categorias hierárquicas, expressões matemáticas)
- Bridge — separa abstração de implementação para que ambas evoluam independentemente (drivers de banco, renderizadores de relatório)
- Flyweight — compartilha eficientemente objetos que ocorrem em grande número (caracteres em um editor de texto, partículas em jogos)
Padrões Comportamentais — Como os Objetos Interagem
Tratam da comunicação entre objetos e da distribuição de responsabilidades.
Strategy
Define uma família de algoritmos, encapsula cada um e os torna intercambiáveis.
| |
Observer
Define uma dependência um-para-muitos entre objetos: quando um muda de estado, todos os dependentes são notificados.
| |
Command
Encapsula uma solicitação como um objeto, permitindo parametrizar operações, enfileirar, logar e desfazer.
| |
Chain of Responsibility, Template Method, State, Iterator, Mediator, Visitor, Memento, Interpreter
Os demais padrões comportamentais cobrem problemas igualmente recorrentes:
| Padrão | Problema que resolve | Uso moderno |
|---|---|---|
| Chain of Responsibility | Processar requisição passando por uma cadeia de handlers até ser tratada | ASP.NET Core Middleware, pipelines |
| Template Method | Define o esqueleto de um algoritmo em uma classe base, deixando partes para subclasses | Base classes de testes, ETL pipelines |
| State | Permite que um objeto altere seu comportamento quando muda de estado | Máquinas de estado, pedidos, workflows |
| Iterator | Percorre uma coleção sem expor sua estrutura interna | IEnumerable<T>, foreach, yield return |
| Mediator | Objetos comunicam-se através de um mediador central — reduz dependências diretas | MediatR, message broker, event bus |
| Visitor | Adiciona operações a objetos sem modificar suas classes | AST visitors, transformações de árvore |
| Memento | Captura e restaura o estado interno de um objeto sem violar encapsulamento | Undo/redo, checkpoints, snapshots |
| Interpreter | Define uma gramática e um interpretador para ela | DSLs, validação de regras de negócio |
GoF é Independente de Linguagem
Um equívoco comum é tratar os padrões GoF como “padrões Java” ou “padrões C++”. O livro original foi escrito com exemplos em C++ e Smalltalk. Mas os padrões são conceitos de design, não APIs.
O mesmo problema, linguagens diferentes
Observer em JavaScript:
| |
Strategy em Python:
| |
Factory em Go:
| |
Por que isso importa em times multidisciplinares?
Quando você tem um time com desenvolvedores C#, Go, Python e TypeScript, os padrões GoF são a lingua franca de design. A conversa:
“Precisamos de um Observer aqui, porque vários módulos precisam reagir quando o status do pedido mudar”
…faz sentido para todos, independentemente da linguagem que cada um usa no dia a dia. Sem esse vocabulário comum, a conversa seria:
“Precisamos de uma classe que quando o status muda, chama uma lista de outras classes que têm um método que… você entendeu”
A Era da Cloud e dos Microserviços
Como a cloud mudou o contexto, não os problemas
A migração para cloud trouxe novos problemas de escala, disponibilidade e distribuição. Mas os problemas fundamentais — acoplamento, coesão, separação de responsabilidades — não mudaram. O que mudou foi onde os problemas aparecem e qual o custo de uma decisão ruim.
| Era | Ambiente | Custo de falha | Escala | Padrão central |
|---|---|---|---|---|
| Monólito | Único servidor | Controlado | Vertical | GoF clássico |
| SOA | Rede interna | Moderado | Moderada | Adapter, Facade |
| Microserviços | Cloud distribuída | Alto (cascata) | Horizontal infinita | Padrões distribuídos |
| Serverless | Cloud efêmera | Variável | Auto-scaling | Stateless por design |
| Híbrido | Misto | Complexo | Heterogênea | Abstração de infra |
Novos padrões para problemas novos
A cloud trouxe uma nova geração de padrões, muitos deles construídos sobre os princípios GoF:
Circuit Breaker (Disjuntor) — o Proxy aplicado a chamadas externas. Detecta falhas em cascata e interrompe chamadas para serviços degradados:
| |
Sidecar — o Decorator aplicado a nível de infraestrutura. Um processo auxiliar que roda ao lado do serviço principal, adicionando responsabilidades (logging, mTLS, rate limiting) sem alterar o código do serviço:
| |
Saga — o Command + Observer aplicado a transações distribuídas. Como não existe transação ACID entre microsserviços, a Saga orquestra uma sequência de transações locais com compensações para falhas:
| |
CQRS (Command Query Responsibility Segregation) — o Command + Strategy aplicado a leitura/escrita:
| |
Cloud vs On-Premises: a decisão arquitetural mais cara
A dicotomia cloud vs on-premises não é técnica — é estratégica e tem implicações arquiteturais profundas:
| Dimensão | Cloud | On-Premises | Híbrido |
|---|---|---|---|
| Escalabilidade | Elástica (paga pelo uso) | Limitada pelo hardware | Burst para cloud |
| Latência | Depende da região | Previsível, baixa | Complexidade de roteamento |
| Conformidade | Varia por cloud/região | Controle total dos dados | Dados sensíveis: on-prem |
| CapEx vs OpEx | OpEx dominante | CapEx dominante | Misto |
| Vendor lock-in | Alto (PaaS/SaaS) | Baixo | Moderado |
| Complexidade ops | Baixa (managed) | Alta (equipe de infra) | Muito alta |
| Padrões de apoio | Adapter (abstrair cloud SDK) | Sem necessidade | Anti-Corruption Layer |
O Adapter como anti-lock-in: times que constroem sobre cloud providers diretamente em todo o código ficam presos. A solução é usar o padrão Adapter para abstrair a infraestrutura:
| |
Times de Desenvolvimento e Times de Sustentação
Esta é, talvez, a dimensão mais subestimada da arquitetura de software. Todo sistema bem-sucedido acaba sendo mantido por pessoas que não o construíram. Às vezes por um time diferente. Às vezes anos depois. Às vezes por desenvolvedores com perfis e habilidades muito diferentes.
O ciclo de vida real de um sistema
| |
Por que os padrões são a memória institucional do sistema
Quando um desenvolvedor novo chega num sistema que usa os padrões GoF de forma consistente, ele não precisa reinventar a leitura do código. Ao ver IStrategy como dependência injetada em uma classe, ele imediatamente entende:
- Essa classe tem comportamento que pode variar
- As implementações estão em outros arquivos, nomeados XXXStrategy
- Para adicionar um novo comportamento, basta criar uma nova implementação
- O código existente não precisa mudar (Open/Closed Principle)
Sem esse vocabulário compartilhado, o mesmo cenário gera:
“Por que há uma interface aqui com apenas uma implementação? Isso parece desperdício.”
…seguido de uma refatoração bem-intencionada que remove a abstração, gerando acoplamento, tornando outro código mais difícil de testar, e quebrando o comportamento em produção.
Diversidade de times: um ativo com custo de coordenação
Times modernos de software são multidisciplinares por necessidade:
| Papel | Foco principal | Perspectiva de arquitetura |
|---|---|---|
| Desenvolvedor Backend | Lógica de negócio, APIs | Padrões de domínio, CQRS, Event Sourcing |
| Desenvolvedor Frontend | UX, performance de render | Padrões de componente, estado global |
| Data Engineer | Pipelines, ETL, analytics | Padrões de dados, streaming |
| DevOps / SRE | Disponibilidade, observabilidade | Padrões de infra, resiliência |
| Arquiteto de Soluções | Integração, domínio | Padrões enterprise, contextos delimitados |
| Tech Lead / Staff Eng | Decisões de plataforma | Todos os níveis |
| Sustentação N1/N2 | Triagem, correções rápidas | Padrões de manutenibilidade |
O risco de times sem linguagem comum:
- Um Data Engineer implementa um pipeline com lógica de negócio que duplica o que já existe no domínio
- Um DevOps cria scripts de deploy que assumem detalhes de implementação que o time de backend mudou
- A sustentação de N2 corrige um bug no Adapter sem entender que há múltiplas implementações, quebrando outra
A arquitetura documentada — com padrões nomeados, decision records (ADRs), e diagramas de contexto — é o que permite que pessoas com perspectivas diferentes contribuam sem colisão.
Architecture Decision Records (ADRs)
Para cada decisão arquitetural relevante, documente:
| |
Esse registro vale ouro para o time de sustentação 3 anos depois. Sem ele, a pergunta “por que tem essa interface?” não tem resposta — e a resposta improvisada costuma ser errada.
Princípios que Sustentam Tudo
Os padrões GoF não existem no vácuo. Eles são expressões práticas de princípios mais fundamentais. Os mais importantes:
SOLID
| Princípio | Definição | Padrão GoF que o expressa |
|---|---|---|
| S — Single Responsibility | Uma classe, uma razão para mudar | Facade (isola responsabilidades), Command |
| O — Open/Closed | Aberto para extensão, fechado para modificação | Strategy, Decorator, Observer |
| L — Liskov Substitution | Subclasses devem ser substituíveis pelas bases | Factory Method, Template Method |
| I — Interface Segregation | Interfaces pequenas e focadas | Adapter, Proxy |
| D — Dependency Inversion | Dependa de abstrações, não de implementações | Todos os padrões via DI |
Coesão e Acoplamento
Alta coesão, baixo acoplamento — talvez o princípio mais antigo e mais violado da engenharia de software.
- Alta coesão: cada módulo/classe faz uma coisa bem feita. Facade, Strategy, Command promovem coesão.
- Baixo acoplamento: módulos têm poucas dependências entre si. Observer, Mediator, Event Bus reduzem acoplamento.
Lei de Demeter (Princípio do Menor Conhecimento)
Um módulo deve conhecer apenas seus colaboradores imediatos — não os colaboradores dos colaboradores.
| |
Armadilhas: Quando Padrões Atrapalham
Padrões aplicados sem julgamento são tão prejudiciais quanto nenhum padrão. Os anti-padrões mais comuns:
Overengineering (“patternite”)
| |
Singleton como variável global
O Singleton é o padrão mais abusado. Quando tudo é Singleton, você essencialmente recria estado global:
| |
Abstração prematura
Não use padrões para problemas que você ainda não tem:
“You Aren’t Gonna Need It” (YAGNI) — não adicione complexidade para necessidades hipotéticas.
A regra prática: quando o problema aparecer pela segunda vez, considere um padrão. Quando aparecer pela terceira, aplique-o.
Conclusão
Os padrões GoF completam 30 anos e continuam na lista de leitura obrigatória de engenheiros de software ao redor do mundo — não por veneração nostálgica, mas porque os problemas que eles resolvem não desapareceram. Nomear soluções para problemas recorrentes é uma das ferramentas mais poderosas da engenharia.
O que mudou não foram os problemas fundamentais, mas o contexto em que eles aparecem:
- Em um monólito, um Observer mal aplicado gera código difícil de ler. Em um sistema distribuído, ele gera uma cascata de falhas que derruba múltiplos serviços.
- Em um projeto de um desenvolvedor, um Singleton sem DI é incômodo. Em um time de 50 pessoas, ele cria dependências ocultas que ninguém vê até o sistema cair em produção.
- Em um ambiente on-premises estático, acoplamento a uma implementação específica é gerenciável. No ecossistema cloud híbrido, ele cria dívidas de migração de meses.
A arquitetura de software — especialmente seus padrões nomeados — é o que permite que sistemas sobrevivam além de sua geração original de desenvolvedores. É o que faz com que um desenvolvedor que entra num projeto hoje possa entender as intenções de design de quem construiu o sistema há 5 anos. É o que faz com que o time de sustentação possa corrigir um bug sem acidentalmente introduzir três novos.
Aprenda os 23 padrões GoF. Não para aplicar todos eles — mas para ter um vocabulário que permite pensar, comunicar e documentar decisões de design com precisão. O software que você escreve hoje alguém vai manter amanhã. Deixe mensagens claras.
Leia Também
- Design de APIs REST: Sem Verbos na URL, Métodos HTTP e Binding de Parâmetros no ASP.NET Core
- Paginação em APIs REST com C# e EF Core 8: Todos os Tipos, Todos os Bancos
- Gargalo em Banco de Dados com C# e EF Core: Mensageria e Paginação
- Programação Assíncrona em C#: async/await do Fundamento à Produção
Referências
- Design Patterns: Elements of Reusable Object-Oriented Software — Gamma, Helm, Johnson, Vlissides (1994) — O livro original do Gang of Four
- A Pattern Language — Christopher Alexander (1977) — A origem intelectual dos padrões de software
- Refactoring: Improving the Design of Existing Code — Martin Fowler — Padrões GoF na prática de refatoração
- Patterns of Enterprise Application Architecture — Martin Fowler — Padrões além do GoF para aplicações corporativas
- Building Microservices — Sam Newman — Padrões de arquitetura para sistemas distribuídos
- Cloud Design Patterns — Microsoft — Catálogo oficial de padrões para cloud (Circuit Breaker, Sidecar, CQRS, Saga, etc.)
- Architecture Decision Records — Michael Nygard — ADRs como memória institucional arquitetural
- SOLID Principles — Robert C. Martin — A base teórica que conecta os padrões GoF
- Repositório blog-zocateli-sample — DesignPatterns — Código-fonte completo dos exemplos deste artigo
Ao comentar, você concorda com nossa Política de Privacidade, Termos de Uso e Política de Exclusão de Dados.