Padrões não são gambiarras
Categories: Design Patterns, Engenharia de software
-
Ultimamente vi uma série de posts no meu feed reader coincidentemente encadeados falando sobre padrões de projeto e os considerando genericamente gambiarras.
Tudo comecou no post do Giovane Roslindo Kuhn falando como é legal usar patterns para a comunicação da equipe. O entendimento que se dá no código quando ele é estruturado seguindo convenções estabelecidas em padrões. Claro que esse não é uma das características de se usar um padrão, mas sim um beneficiamento dele (mesmo quando evidentemente não necessitaria haver a presença de um padrão).
Motivado por esse post, o Vítor Ferreira Pamplona escreveu um outro dedicado aos anti-patterns e a prejudicial característica da comunidade java ser reconhecida como a comunidade pattern. Evidenciou a necessidade que programadores empolgados com uma nova linguagem agirem como se essa linguagem fosse uma bala-de-prata e resolvesse todos e quaisquer problemas.
Os próprios padrões de projeto conhecidos podem se tornar um anti-pattern se forem usados para um contexto diferente do que se propõe inicialmente. Quem nunca viu aí uma estrutura cheia de commands para simular MVC em um sistema web levante a mão.
Após o post do Vítor o Thiago Arrais publicou um artigo chamando os padrões de "gambiarra com nomes" que acabou gerando outro artigo do Marcos Tapajós no blog da Improve It na mesma linha.
Concordo com muitos pontos colocados por ambos mas quero fazer uma ressalva, uma gambiarra é uma solução improvisada (deveria também ser temporária) e fora dos procedimentos legais. Um padrão pode ser uma gambiarra mas em essência não é.
Gambiarra "Orientação a Objetos"
Se levarmos ao pé da letra essa consideração podemos então supor que Orientação a objetos seria uma gambiarra, porque os desenvolvedores C já simulavam os conceitos de orientação antes do surgimento do C++, que apenas forneceu ADTs nativos específicos para o desenvolvedor. Linguagens como Smalltalk que foram concebidas tendo em mente a orientação a objetos seria únicas verdadeiras OO mesmo que internamente seu interpretador faça algo parecido com uma linguagem não pura. Mas a única diferença entre as duas é a familiaridade da arquitetura interna da linguagem com o padrão/conceito que se deseja implementar. Uma esconde do desenvolvedor a implementação a outra temos que criar nosso próprio dialeto e não se beneficiar das otimizações e checagens que por ventura a plataforma faça.
Vícios
Temos programadores que acham que podem viver conhecendo apenas uma linguagem e que esta deve servir para tudo, com isso aceitam estruturas estabelecidas mesmo que sejam nocivas.
A Sun criou o conceito de Java Beans para componentes visuais e extendeu esse conceito para sua plataforma Enterprise para designar ADTs que encapsulam suas propriedades.
Hoje a maioria dos desenvolvedores quando codificam suas classes o fazem com um passo-a-passo em mente:
- Cria uma classe que representa uma tabela no banco de dados;
- Cria as propriedades referentes as colunas nessa tabela;
- Atribui private para todas as propriedades;
- E por fim cria métodos "set" e "get" para todas as propriedades indiscriminadamente.
Se voce criar uma construção que acesse "objeto.propriedade" é pecado mortal em java, não segue a "convenção".
Em linguagens que implementam o ECMAscript voce tem no BOM (Browser Object Model) o método setProperty(chave, valor) nativo que atribui um valor à propriedade indicada e não necessita implementar um atribuidor para cada método. Sabiamente não existe um getProperty, voce acessa diretamente.
Em java se uma propriedade é read-only tem coerência voce aplicar um private no qualificador e criar um método getX, outra situação é se voce deseja manipular o valor em tempo de execução, então um método get e ou set tem necessidade. Fora isso é desnecessário e a propriedade é pública.
Generalidade vs Especificidade
O problema maior com padrões é querer extender uma linguagem além do que ela foi arquiteturada. Como simular Continuations que é nativo da linguagem Scheme, ou Design By Contract do Eiffel. Voce pode fazer ambos em Java, tanto Continuations como DbC podem ser feitas mas com gambiarras, não são inerentes da arquitetura concebida na plataforma Java. Existem até Framework e Container Java que implementam continuations, mas sofridamente.
Inclusive alguns entusiastas do Ruby mais afoitos (A.K.A novatos) fazem bastante algazarra em listas de discussões de como conseguem fazer uma iteração ou outra operação específica com menos linha de código que linguagens como Java ou C++. Claro que é perda de tempo total tentar dialogar e mostrar a necessidade da escolha ideal para o determinado propósito, os programadores de verdade sabem que Ruby também não será o fim dos tempos, conceitos surgirão e retornarão dependendo da situação.
Outra situação depende do ambiente, como simular MVC em uma ambiente web, devido a diferença de contexto do ambiente http em detrimento ao ambiente standalone de um desktop surgiu o famigerado MVC model 2 que deu cria a aberrações como Struts e derivados. Isso hoje pode ser contornado mas ainda é incipiente.
Na mesma forma acontece com padrões, como o contexto de uma linguagem está atrelada a determinado ambiente é vital incorporar conceitos deste contexto na sua semântica e deixar a extensão para o desenvolvedor do que ser genérica e causar improdutividade com tarefas repetitivas, vide sucesso do ruby na construção de aplicações web com o Ruby On Rails.
Em diversas épocas os padrões como Singleton e Factory vão e voltam com desenvoltura, em momento amado e indispensável, outro odiado e suplantado. Mas são padrões universais para resolver um determinado problema, catalogado e disponível para quando forem requisitados.
Padrões são assim, como quase tudo na vida, desnecessários as vezes e se usados com moderação são benéficos. Como dizia minha vó, "tudo demais é veneno".


