Back-End

20 set, 2018

Os tradicionais Padrões de Projeto em JavaScript

Publicidade

A maioria dos desenvolvedores preocupam-se em escrever códigos legíveis, de fácil manutenção e reutilização. Por isso, uma base de código bem estruturada é muito importante para as grandes aplicações. Padrões de projetos provêm uma solução padronizada, documentada e testada para um problema de design de grandes projetos que aparecem recorrentemente.

Design Patterns: Elements of Reusable Object-Oriented Software (1994)

O livro mais emblemático sobre Padrões de projeto é o Design Patterns: Elements of Reusable Object-Oriented Software. Graças a Gang of Four (GoF), passamos a ter um catálogo de padrões que se tornaram um vocabulário comum entre diferentes projetos e, o melhor de tudo, independente de linguagem de programação.

O problema da tradução Padrões de Projeto

Não quero fazer uma inquisição com essa seção, mas traduzir Design Patterns como Padrões de Projeto fez com que boa parte do significado original perca o sentido. Os padrões estão fortemente associados ao processo de design de uma determinada solução. Por mais que possamos utilizar linguagens de propósito geral, estamos o tempo inteiro renovando a forma como os problemas são resolvidos, como podemos acompanhar nos trabalhos do TC39.

O que é um Design Pattern de fato

Os padrões são uma estratégia de design para resolver um determinado problema. Por exemplo, imagine que gostaríamos que representar um Cubo Mágico utilizando JavaScript. Qual das estratégias a seguir seria mais prática?

// Estratégia 1
const cubos = []
cubos[0] = []
cubos[0][0] = []
cubos[0][0][0] = "cubo 1"
cubos[0][0][1] = "cubo 2"
cubos[0][0][2] = "cubo 3"
// [...]

// Estratégia 2
const faces = [
    "U1", "U2", "U3", "U4", "U5", "U6", "U7", "U8", "U9",
    "L1", "L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9",
    "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9",
    "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9",
    "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9",
    "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9",
]

O primeiro passo para pensar em qual das duas estratégias adotar é verificar qual é a coisa mais importante para o problema. Nós queremos visualizar as faces ou realizar os movimentos? A nossa necessidade é ser compatível com a API do JavaScript de iteração? Queremos realizar uma permutação no cubo?

Design Patterns são úteis para expressar, discutir, registrar e analisar as vantagens e desvantagens de uma abordagem para um problema. Outro ponto que acabamos de ver sobre Design Patterns é que servem para contornar as limitações das linguagens de programação. Essa informação é tão importante que está escrito no livro de Design Patterns:

A escolha da linguagem de programação é importante porque influencia o ponto de vista. Nossos padrões assumem características de linguagem no nível de Smalltalk/C ++, e a escolha determina o que pode ou não ser implementado facilmente. Se tivéssemos assumido linguagens procedurais, talvez tivéssemos incluído padrões de projeto como “Herança”, “Encapsulamento” e “Polimorfismo”.

Da mesma forma, alguns dos nossos padrões são suportados diretamente pelas linguagens orientadas a objetos menos comuns. CLOS tem multi-method, por exemplo, que diminuem a necessidade de um padrão, como Visitor. De forma similar, existem diferenças suficientes entre Smalltalk e C ++ para significar que alguns padrões podem ser expressos mais facilmente em uma linguagem do que na outra.

~ Design Patterns — Elements of Reusable Object-Oriented Software

Porque Design Patterns são uma má ideia

A existência de padrões catalogados é muito positiva, porém, nós ainda temos um preciosismo muito grande pelos padrões tradicionais. O principal problema é que os tempos mudam, as linguagens evoluíram e boa parte dos padrões simplesmente perderam o sentido.

Outro problema com os Padrões de Projeto é que por mais que sejam universais, eles não são aplicáveis em todas as linguagens. Peter Norvig fez uma apresentação onde 16 dos 23 Design Patterns encontrados no livro são mais simples ou até mesmo invisíveis em linguagens com características semelhantes a LISP.

Padrão de Classe Encapsulada

No EcmaScript existe um Design Pattern para criação de classes que era muito utilizado antes do EcmaScript 6. Ele acabou caindo em desuso quando as classes foram introduzidas. Porém, são dignos para exemplificar um Design Pattern invisível dentro de uma linguagem:

Exemplo de Classe Encapsulada em EcmaScript 5

function Person(name) {
   this.name = name;
}

Person.prototype.saysHello = function () {
   return "Hello, my name is " + this.name;
};

function Employee(name, title) {
   Person.call(this, name);
   this.title = title;
}

Employee.prototype = new Person();
Employee.prototype.constructor = Employee;

Employee.prototype.describe = function () {
   var parent = Person.prototype.saysHello.bind(this);
   return parent() + " (" + this.title + ")";
};

Desde a introdução de classes no EcmaScript 6, esse design caiu em desuso em favor do açucar sintático que torna esse padrão invisível, conforme podemos observar a seguir:

class Person {
   constructor(name) {
      this.name = name;
   }

   saysHello() {
      return "Hello, my name is " + this.name;
   }
}

class Employee extends Person {
   constructor(name, title) {
      super.constructor(name);
      this.title = title;
   }

   describe() {
      return super.saysHello() + " (" + this.title + ")";
   }
}

Não precisamos dizer para os outros que estamos fazendo um Padrão de Classe Encapsulada quando se trata de EcmaScript 6, pois ele simplesmente existe como algo intrínseco na linguagem. O padrão acabava por ser uma alternativa para estrapolar as limitações da linguagem para a nossa escolha de expressão.

Além disso, afirmar que estamos implementando um Padrão de Classe Encapsulada não torna o nosso código melhor e nem pior, nós simplesmente escolhemos um Design para ele, uma forma de expressão. Conforme já foi dito por Ralph E. Johnson, conformidade com os padrões não é uma medida de qualidade.

Considerações finais

Conforme o que foi apresentado, podemos concluir que a definição dos padrões de projetos deve ocorrer como etapa do processo de design de um determinado problema e, principalmente, não são uma medida de qualidade. Os padrões devem ser utilizados como um meio para atingir um fim e não como um fim.

Referências bibliográficas