Kohelet, o mais desencantado dos livros, diz que nada há de novo sob o sol: o que foi é o que será, e o problema que hoje parece inédito já atormentou alguém antes. Em engenharia de software isso é libertador, não deprimente. O problema de projeto que você encara agora, como criar objetos sem acoplar ao tipo concreto, como notificar muitos quando um muda, como trocar um algoritmo em tempo de execução, já foi resolvido inúmeras vezes, e as boas soluções foram catalogadas. Design patterns são essas formas conhecidas: não código para copiar, mas soluções nomeadas para problemas que recorrem. Reconhecer que o problema não é novo é o primeiro passo para não reinventar, mal, a roda que já gira bem.
01Soluções catalogadas para problemas que voltam
Em 1994, quatro autores, Gamma, Helm, Johnson e Vlissides, que ficaram conhecidos como a Gang of Four, publicaram um livro que catalogou vinte e três padrões de projeto orientado a objetos. A ideia veio da arquitetura de edifícios, de Christopher Alexander, que percebera que boas soluções de projeto se repetem e podem ser descritas como padrões reutilizáveis. Cada padrão do catálogo descreve um problema recorrente, a solução testada, e as consequências de aplicá-la. Não é código pronto; é a forma da solução, adaptável à sua linguagem e ao seu caso.
O valor está em não começar do zero diante de um problema estrutural conhecido. Quando você precisa garantir uma única instância de algo, existe o Singleton, com suas armadilhas conhecidas; quando precisa notificar vários interessados sobre uma mudança, existe o Observer; quando precisa trocar um comportamento em tempo de execução, existe o Strategy. Conhecer o catálogo é ter, na cabeça, um repertório de soluções provadas para os problemas que a orientação a objetos faz recorrer, e reconhecer o padrão certo no problema à frente é o que separa quem projeta com repertório de quem improvisa cada vez.
Figura 1As três categorias de padrões da Gang of Four
CRIACriacionaiscomo criar objetos sem acoplar ao tipo concreto
ESTREstruturaiscomo compor objetos em estruturas maiores
COMPComportamentaiscomo objetos colaboram e distribuem responsabilidade
EX1Factory, Buildercriacionais: fabricar sem revelar a classe concreta
EX2Adapter, Decoratorestruturais: adaptar e envolver sem herança rígida
Vinte e três padrões em três categorias, catalogados pela Gang of Four em 1994. Cada um descreve um problema recorrente, a solução testada e suas consequências. Não é código pronto, é a forma da solução.
02As três famílias, e o que cada uma resolve
Os padrões se dividem em três famílias pela natureza do problema que atacam. Os criacionais lidam com a criação de objetos, desacoplando o código de quem cria dos tipos concretos que ele instancia: o Factory Method e o Abstract Factory delegam a decisão de qual classe criar, o Builder monta objetos complexos passo a passo, o Singleton controla a instância única. Os estruturais lidam com a composição: o Adapter faz duas interfaces incompatíveis conversarem, o Decorator adiciona comportamento envolvendo o objeto sem herança, o Facade dá uma porta simples para um subsistema complexo.
Os comportamentais, a maior família, lidam com como os objetos colaboram e distribuem responsabilidade. O Observer notifica muitos interessados quando um sujeito muda, base de toda arquitetura orientada a eventos. O Strategy encapsula algoritmos intercambiáveis atrás de uma interface comum. O State faz um objeto mudar de comportamento conforme seu estado interno. O Command transforma uma requisição em objeto, permitindo fila, desfazer e log. Não é preciso decorar os vinte e três; é preciso entender as três famílias e reconhecer, diante de um problema, a que família ele pertence, porque isso já aponta para o punhado de padrões que valem consultar.
Figura 2Padrões clássicos por família, e o que resolvem
Padrão
Família
Problema que resolve
Factory Method
criacional
criar objeto sem acoplar à classe concreta
Builder
criacional
montar objeto complexo passo a passo
Adapter
estrutural
fazer interfaces incompatíveis conversarem
Decorator
estrutural
adicionar comportamento sem herança rígida
Observer
comportamental
notificar muitos quando um sujeito muda
Strategy
comportamental
trocar o algoritmo em tempo de execução
Não é preciso decorar os vinte e três. Entender as três famílias e reconhecer a que família o problema pertence já aponta para o punhado de padrões que valem consultar.
03O maior valor não é o código, é o vocabulário
O ganho mais subestimado dos design patterns não está no código que eles produzem, está na linguagem que eles criam. Quando um engenheiro diz aqui eu usei um Observer, ou isto pede um Strategy, ou cuidado com esse Singleton, o time inteiro entende uma ideia complexa numa palavra. O padrão vira uma unidade de comunicação, um substantivo compartilhado que comprime um parágrafo de explicação em um termo. É o mesmo poder da linguagem ubíqua do DDD: nomear bem para pensar e comunicar melhor.
Sem esse vocabulário, cada discussão de design recomeça do chão, descrevendo a estrutura em detalhe toda vez. Com ele, a conversa opera num nível mais alto, e o code review fica mais rico: revisar deixa de ser só ler linhas e passa a ser reconhecer intenções nomeadas. É por isso que conhecer os padrões vale mesmo para quem raramente implementa um do zero: o valor de conseguir ler o código dos outros e das bibliotecas, que estão cheias deles, e de participar da conversa de arquitetura como quem fala a língua, supera o de escrever mais um Factory. Nada há de novo sob o sol, e ter nome para o que recorre é o que permite ao time construir sobre o conhecido em vez de redescobri-lo a cada projeto.
Figura 3O padrão como unidade de comunicação no time
01Sem vocabuláriocada discussão descreve a estrutura em detalhe, do zero
02Nomear o padrão'isto é um Observer' comprime um parágrafo numa palavra
03Conversa mais altaa arquitetura se discute em intenções, não em linhas
04IACode review mais ricorevisar vira reconhecer intenções nomeadas
05Ler o dos outrosbibliotecas e código alheio ficam legíveis pelo repertório
↺ Ter nome para o que recorre permite construir sobre o conhecido, em vez de redescobri-lo a cada projeto. É o mesmo poder da linguagem ubíqua do DDD.
O maior valor dos padrões não é o código, é a linguagem. O padrão vira substantivo compartilhado, e a conversa de design opera num nível mais alto. Vale mesmo para quem raramente implementa um do zero.
04A armadilha: padrão em busca de problema
O perigo dos design patterns é o entusiasmo. Quem acaba de aprender o catálogo tende a ver padrões em todo lugar e a aplicá-los onde não há problema que os justifique, o clássico cargo cult: reproduzir a forma sem entender a necessidade. O resultado é o código enfeitado de Factories, Strategies e Decorators que ninguém pediu, com camadas de indireção que só existem porque o padrão era conhecido, não porque o problema existia. Padrão aplicado sem problema é complexidade pura, e piora exatamente o que os padrões deveriam melhorar: a legibilidade e a facilidade de mudar.
A regra madura é que o padrão responde a um problema, não o contrário. Você não sai procurando onde encaixar um Visitor; você encontra um problema de projeto, reconhece que ele recorre, e lembra que existe uma solução conhecida para ele. O código mais simples que resolve o problema de hoje quase sempre vence o código elaborado que resolve o problema imaginado de amanhã. Design patterns são ferramentas na caixa, e a marca do artesão não é usar todas em cada peça, é escolher a certa para o corte à frente, e muitas vezes a ferramenta certa é a mão livre, sem padrão nenhum. Nada de novo sob o sol vale para os problemas; não é licença para inventar problema só para usar a solução.
Figura 4Quando o padrão ajuda: existe o problema contra a complexidade que ele adiciona
O problema que o padrão resolve existe de fato ↑
Use o padrãoproblema real, complexidade justificada: a solução conhecida rende.
Use com parcimôniaproblema real, mas padrão pesado: veja se há solução mais simples antes.
Padrão leve, sem problemanão há problema, mas o padrão custa pouco: ainda assim, indireção à toa.
Cargo cultnão há problema e o padrão é pesado: complexidade pura, piora o que devia melhorar.
Complexidade que o padrão adiciona →
O padrão responde a um problema, não o contrário. Aplicá-lo sem problema é cargo cult: reproduz a forma sem a necessidade. A marca do artesão é escolher a ferramenta certa, e às vezes é a mão livre.
05A maturidade com padrões, e onde eles se apoiam
A relação com padrões amadurece em fases reconhecíveis. Primeiro o desconhecimento, reinventando soluções mal. Depois a descoberta empolgada, aplicando padrões em tudo, a fase do cargo cult. Então a reação, às vezes rejeitando padrões por inteiro depois de se queimar com o excesso. E por fim o julgamento: reconhecer o problema recorrente, saber que há solução conhecida, e aplicá-la com parcimônia, ou não aplicá-la, conforme a complexidade se justifique. O objetivo nunca foi usar padrões; foi resolver bem, e padrões são um meio entre outros.
Design patterns assentam sobre o SOLID, cujos princípios muitos padrões materializam, o Strategy é aberto-fechado em ação, o Observer é inversão de dependência, e sustentam o que vem por cima, a arquitetura limpa e o design orientado a eventos, feitos de padrões combinados. Mas a lição de Kohelet corta os dois jeitos: nada de novo sob o sol significa que a solução para o seu problema provavelmente já existe, e vale conhecê-la; e significa também que a moda de arquitetura que hoje parece revolucionária é, quase sempre, um padrão antigo com nome novo. Repertório sem dogma, reconhecer o velho no novo e a solução no problema, é o que a maturidade com padrões entrega.
Figura 5Maturidade na relação com design patterns
0Desconhecereinventa soluções, mal, a cada problema
1Descobreaprende o catálogo e se empolga
2Cargo cultaplica padrão em tudo, indireção sem problema
3Reagerejeita padrões por inteiro, queimado pelo excesso
4Julgareconhece o problema, aplica com parcimônia ou não aplica
5Repertório vivovê o velho no novo, a solução no problema, sem dogma
O objetivo nunca foi usar padrões, foi resolver bem. A fase 2, cargo cult, e a 3, rejeição, são passagens comuns. A maturidade é repertório sem dogma: reconhecer o velho no novo e a solução no problema.
Para levar
Design patterns partem de Kohelet: nada há de novo sob o sol, e o problema de projeto que parece inédito já foi resolvido e catalogado pela Gang of Four. As três famílias, criacionais, estruturais e comportamentais, dão soluções provadas, mas o maior valor é o vocabulário, o substantivo compartilhado que faz o time entender uma ideia numa palavra. A armadilha é o cargo cult, o padrão em busca de problema, e a maturidade é o repertório sem dogma. A IA reconhece o padrão e desmascara o excesso. O fim, porém, nunca foi usar padrões, foi resolver bem, e às vezes a ferramenta certa é a mão livre.
Tags
#julianovincedecampos
#DesignPatterns
#Engenharia
#GangOfFour
#OrientaçãoAObjetos
#Arquitetura
#DesignDeSoftware
Quem escreve: Juliano Vince de Campos
Gerente de Operações, Tecnologia e Infraestrutura (SRE) numa central de registros. Trabalho com tecnologia desde 2009 e com cibersegurança em tempo integral desde 2015, em infraestrutura crítica, fintech e banking. Escrevo sobre o que eu opero: confiabilidade, segurança, governança e IA que passa por gate antes de chegar em produção.