Language Agnostic

Design patterns são universais

Demonstrando profundidade técnica independente de linguagem

21 de jul. de 2025·Ricardo Coelho

Um candidato em entrevista descreve como resolveu um problema de acoplamento entre módulos em um sistema Python usando injeção de construtor e uma fábrica que decide qual implementação concreta retornar em função de configuração. O entrevistador, que opera em Java há quinze anos, reconhece imediatamente o desenho: é o mesmo Abstract Factory que ele usou em três sistemas diferentes. O candidato não citou o nome, e o entrevistador não precisou ouvir o nome pra reconhecer o mecanismo. Pra mim, esse reconhecimento cruzado é o que separa uma entrevista que avalia raciocínio de uma entrevista que avalia vocabulário.

Design patterns não pertencem a linguagens. São respostas repetidas a problemas estruturais que aparecem sempre que sistemas crescem além de uma certa complexidade. O Gang of Four (os quatro autores do clássico Design Patterns, de 1994) descreveu vinte e três desses padrões usando C++ e Smalltalk como veículos, e o catálogo sobreviveu trinta anos não porque o livro fosse sagrado, mas porque os problemas que ele descreve continuam aparecendo em toda linguagem orientada a objetos, e variações dos mesmos problemas aparecem em linguagens funcionais, em linguagens de sistemas e em linguagens dinâmicas. O padrão Observer aparece como event emitters em Node.js, como sinais em Django, como LiveData em Android, como @Published em Swift, como streams reativos em Rx. A forma sintática varia, mas o mecanismo não: um sujeito mantém uma lista de dependentes e notifica cada um quando seu estado muda, desacoplando produtor e consumidor no tempo.

Na minha avaliação, o candidato que demonstra profundidade técnica numa entrevista language agnostic é aquele que descreve o mecanismo antes de mencionar o nome, e menciona o nome apenas quando ele economiza palavras. Dizer “usei um Strategy” sem explicar o problema que o Strategy resolveu naquele contexto é vocabulário. Descrever o cenário de três políticas de cálculo de frete que mudavam por cliente, onde a condicional crescia a cada novo contrato até que a decisão fosse encapsular cada política num objeto com a mesma interface e injetar a política correta no momento da composição, isso é engenharia. O nome Strategy aparece ao final como etiqueta de conveniência sobre a solução já construída, e o entrevistador experiente reconhece a diferença em segundos.

Em entrevistas cross-stack, o efeito é ainda mais claro. Um candidato com background em Go descreve um problema de inicialização custosa de um cliente HTTP compartilhado entre goroutines e a solução baseada em sync.Once pra garantir construção única e thread-safe. Um entrevistador Java reconhece o Singleton com double-checked locking; um entrevistador Python reconhece o módulo como singleton natural resolvido pelo próprio sistema de imports; um entrevistador Kotlin reconhece o object declaration. A linguagem dita a ergonomia da implementação, mas o problema (construção única, acesso global controlado, visibilidade segura sob concorrência) é compartilhado. Candidatos que articulam o problema em termos de invariantes e garantias atravessam fronteiras de stack sem atrito.

Existem armadilhas previsíveis. Tratar padrões como cardápio a ser aplicado é a mais comum: um engenheiro que escreve um Factory pra cada nova classe e um Decorator pra cada variação comportamental pequena está demonstrando falta de julgamento sobre quando complexidade estrutural se paga. Padrões são respostas a pressões que o código já está sofrendo. Também vale ignorar o fato de que algumas linguagens tornam padrões redundantes: Iterator é construção nativa em quase toda linguagem moderna, Command se dissolve em funções de primeira classe nas funcionais, e Visitor costuma ser substituído por pattern matching sobre tipos algébricos em Scala, Rust, Kotlin moderno, Java 21. Descrever esses padrões como estruturas de classes quando a linguagem oferece a construção diretamente é sinal de que o candidato aprendeu o livro sem aprender a intenção. Há ainda o erro de confundir padrões estruturais com padrões arquiteturais, com o vocabulário se sobrepondo e o entrevistador desatento não distinguindo. Repository, Unit of Work, CQRS, Event Sourcing, Saga são padrões de arquitetura de aplicação, não padrões de objeto. Eles resolvem problemas de consistência distribuída e coordenação de transações de longa duração, com separação entre leitura e escrita quando o caso pede. Confundir esse nível com o nível do Gang of Four empobrece a conversa. Um candidato que distingue os dois níveis e conecta cada um ao problema que ele endereça demonstra maturidade que não se constrói lendo o livro uma vez.

A consequência prática pra quem conduz entrevistas é direta. A pergunta produtiva não é “quais design patterns você conhece”, mas “descreva um problema de acoplamento ou duplicação que você resolveu estruturalmente e o que te fez escolher aquela estrutura”. A primeira mede memorização, a segunda mede raciocínio. Candidatos fortes responderão com mecanismos, invariantes e trade-offs, e o entrevistador reconhecerá os padrões nas descrições sem precisar das etiquetas. Candidatos que só sabem etiquetas tropeçarão na segunda pergunta, independentemente da linguagem em que trabalham.

A consequência prática pra quem está sendo entrevistado é simétrica. Preparar-se pra uma entrevista técnica relendo a lista de vinte e três padrões e decorando diagramas UML é esforço mal alocado. Na minha análise, o retorno vem de revisitar sistemas reais nos quais se trabalhou, reconstruir mentalmente os problemas que forçaram cada decisão estrutural, e articular essas decisões em termos que independam da sintaxe da linguagem em que foram implementadas. Um engenheiro que descreve seu próprio código em termos de pressões, garantias e invariantes demonstra profundidade que sobrevive a qualquer mudança de stack. E essa profundidade é exatamente o que uma entrevista language agnostic existe pra encontrar.