A Estrutura do Código: Organizando o JavaScript

Um grande design é produto de cuidado e atenção aplicados em áreas que são importantes, resultando em uma útil, compreensível e, provavelmente, uma bela interface do usuário. Mas não seja tão tolo pensando que design fica somente a cargo dos designers.

Há muito de design em códigos, e eu não falo somento do código que cria a interface do usuário — Eu falo sobre o design do código1.

Um código bem projetado é muito mais fácil de manter, otimizar e estender, aumentando a eficiência dos desenvolvedores. Isso significa que mais concentração e energia serão gastos em construir grandes coisas, o que faz a todos feliz — usuários, desenvolvedores e demais partes interessadas.

Há três aspectos de alto nível e universais entre as linguagens de programação que são particularmente importantes na estrutura do código:

  • Arquitetura do sistema — O layout básico do código base (codebase / core). Regras que governam como os diversos componentes, como modelos, visualizações e controladores, interagem entre si.
  • Manutenibilidade — O quão bem o código pode ser otimizado e estendido?
  • Reusabilidade — O quão reutilizáveis são os componentes da aplicação? Com que facilidade cada uma das implementações de um componente podem ser customizadas?

Em linguagens mais flexíveis, especificamente JavaScript, é necessário um pouco mais de disciplina para desenvolver um código bem escrito. O ambiente JavaScript é tão indulgente que é fácil jogar peças e pedaços por todos os lados e ainda assim ter a aplicação funcionando. Estabelecendo uma arquitetura de sistema o mais brevemente possível (e permanecendo nela!) provê consistência ao seu código base, garantindo uma estrutura mais sólida.

Uma abordagem que eu gosto consiste em um padrão de design de software testado e aprovado, o padrão modular, cuja estrutura extensível presta-se a uma arquitetura de sistema sólida e um código base de fácil manutenção. Eu gosto de construir módulos dentro de um plugin jQuery, que contribui para uma ótima reutilização, oferece opções robustas, e possui uma API bem trabalhada.

Abaixo, eu demonstrarei como codificar componentes bem organizados e que podem ser reutilizados em projetos futuros.

O padrão modular

Há muitos padrões de projeto por aí, e, igualmente, muitos recursos para eles. Addy Osmani escreveu um fantástico livro (gratuito!) sobre estruturas de codificação em JavaScript, que eu altamente recomendo para desenvolvedores em qualquer nível.

O padrão modular é uma simples base estrutural que pode ajudar a manter seu código limpo e organizado. Um módulo é apenas um objeto que contêm métodos e propriedades, e esta simplicidade é a melhor coisa sobre esse padrão: até mesmo pessoas não familiarizadas com os tradicionais padrões de arquitetura de softwares conseguirão olhar para o código e entender imediatamente como ele funciona.

Em aplicações que utilizam esse padrão, cada componente tem seu próprio módulo. Por exemplo, para construir uma função de autocompletar, você terá que criar um módulo para o "textfield" e um módulo para a lista de resultados. Esses dois módulos podem trabalhar juntos, mas o código para o "textfield" não poderá manipular o código para lista de resultados, e vice-versa.

Essa dissociação dos componentes é o motivo do padrão modular ser ótimo para construir uma arquitetura de sistema sólida. As relações entre os componentes estão bem definidas, não espalhadas por todo o código base — qualquer coisa relacionada ao "textfield" é manipulada pelo módulo de "textfield" — resultando em um código limpo.

Outro benefício dessa organização em módulos é a fácil manutenção do todo. Módulos podem ser otimizados e estendidos independentemente, sem afetar qualquer outra parte da aplicação.

Eu usei o padrão modular para a estrutura básica do jPanelMenu, o plugin jQuery que desenvolvi para sistemas de menu off-canvas. Utilizarei ele como exemplo para ilustrar o processo de construção de um módulo.

Desenvolvendo um módulo

Para começar, defini três métodos e propriedades que são utilizados para gerir as interações no sistema do menu.

  1. var jpm = {
  2. animated: true,
  3. openMenu: function( ) {
  4. this.setMenuStyle( );
  5. },
  6. closeMenu: function( ) {
  7. this.setMenuStyle( );
  8. },
  9. setMenuStyle: function( ) {}
  10. };

A ideia é dividír o código em pedaços pequenos e reutilizáveis, o menor possível. Poderia ter codificado apenas um método toggleMenu( ), porém criando os métodos openMenu( ) e closeMenu( ) separadamente provê maior controle e reutilização entre os módulos.

Note que as chamadas para os métodos e propriedades do módulo, dentro do próprio módulo (como as chamadas para setMenuStyle ( )), são prefixadas com a palavra-chave "this" — este é o modo como os módulos acessam os seus próprios membros.

É essa a estrutoura básica de um módul. Você pode continuar a adicionar métodos e propriedades como necessitar, mas isso não ficará mais complexo do que está. Depois da estrutura base em seu lugar, a camada de reutilização — options e uma API exposta — pode ser construída por cima disto.

plugins jQuery

O terceiro aspecto de um código bem estruturado é provavelmente o mais crucial: reusabilidade. Este tópico vem com uma advertência: embora haja formas óbvias de construir e implementar componentes reutilizáveis em JavaScript (o nosso módulo acima é 90% de JavaScript) eu prefiro contruir plugins em jQuery para aplicações mais complexas, por algumas razões.

A mais importante, é uma forma de comunicação discreta. Se você utilizar jQuery para desenvolver um componente, deve tornar isso óbvio para quem está implementando ele. Desenvolver um componente como um plugin jQuery é uma ótima forma de dizer que o jQuery é requerido.

Além disso, o código base será coerente com o resto do código do projeto, baseado em jQuery. Isto é bom por razões estéticas, mas quer dizer também (por extensão) que os desenvolvedores podem prever como interagir com o plugin sem ter que pesquisar muito. Apenas uma maneira melhor de construir uma boa interface de desenvolvimento.

Antes de você começar a desenvolver um plugin jQuery, assegure-se de que o plugin não entre em conflito com as outras bibliotecas JavaScript que utilizam a notação "$". É muito mais simples do que soa — apenas envolva o código do seu plugin como está abaixo:

  1. (function($) {
  2. // Código do plugin em jQuery aqui
  3. })(jQuery);

Em seguida, montamos o nosso plugin ao jogar o nosso módulo, previamente codificado, dentro do que acabamos de escrever. Um plugin é somente um método definido em um objeto jQuery ($).

  1. (function($) {
  2. $.jPanelMenu = function( ) {
  3. var jpm = {
  4. animated: true,
  5. openMenu: function( ) {
  6. this.setMenuStyle( );
  7. },
  8. closeMenu: function( ) {
  9. this.setMenuStyle( );
  10. },
  11. setMenuStyle: function( ) {}
  12. };
  13. };
  14. })(jQuery);

Tudo o que você tem que fazer para utilizar o plugin é chamar a função que você acabou de criar.

var jpm = $.jPanelMenu( );

Options

Options são essenciais em um plugin verdadeiramente reutilizável porquê elas permitem customizações em cada implementação. Cada projeto traz consigo uma série de estilos de desenvolvimento, tipos de interação e estruturas de conteúdo. Options customizáveis ajudam a assegurar que você pode adaptar o plugin para se encaixar nas necessidades do projeto.

É uma boa prática prover bons valores padrão para as suas options. A melhor forma de fazer isso é usando o método $.extend( ) do jQuery , que aceita (pelo menos) dois parâmetros.

Para o primeiro parâmetro defina um objeto com todas as options disponíveis e seus valores padrão. Como segundo parâmetro, forneça o objeto recebido com as options. Isso irá mesclar os dois objetos, sobrescrevendo os valores padrão com qualquer opção fornecida.

  1. (function($) {
  2. $.jPanelMenu = function(options) {
  3. var jpm = {
  4. options: $.extend({
  5. 'animated': true,
  6. 'duration': 500,
  7. 'direction': 'left'
  8. }, options),
  9. openMenu: function( ) {
  10. this.setMenuStyle( );
  11. },
  12. closeMenu: function( ) {
  13. this.setMenuStyle( );
  14. },
  15. setMenuStyle: function( ) {}
  16. };
  17. };
  18. })(jQuery);

Além de proporcionar uma boa estrutura, as options tornam-se quase auto-documentadas — alguém pode olhar para o código e ver todas as opções disponíveis imediatamente.

Exponha tantas options quanto for possível. A personalização vai ajudar em futuras implementações, além de que flexibilidade nunca é demais.

API

Options são uma forma magnífica de customizar o funcionamento de um plugin. Uma API, por outro lado, habilita extensões para a funcionalidade do plugin, expondo métodos e propriedades que favorecerão a implementação do código.

Enquanto é ótimo expor o quanto for necessário por meio de uma API, o mundo exterior não deve ter acesso a todos os métodos e propriedades internas. O ideal seria expor apenas os elementos que seriam utilizados.

Em nosso exemplo, a API exposta deveria incluir chamadas para abrir e fechar o menu, nada mais. O método interno setMenuStyle( ) roda no intervalo entre o menu abrir e fechar, porém não deve ser acessado pelo meio público.

Para expor uma API, retorne um objeto com todos os métodos e propriedades desejadas ao final do código do plugin. Você pode até mesmo retornar métodos e propriedades para aqueles que estão dentro do módulo — é aqui que uma bela organização de padrão modular realmente brilha.

  1. (function($) {
  2. $.jPanelMenu = function(options) {
  3. var jpm = {
  4. options: $.extend({
  5. 'animated': true,
  6. 'duration': 500,
  7. 'direction': 'left'
  8. }, options),
  9. openMenu: function( ) {
  10. this.setMenuStyle( );
  11. },
  12. closeMenu: function( ) {
  13. this.setMenuStyle( );
  14. },
  15. setMenuStyle: function( ) {}
  16. };
  17. return {
  18. open: jpm.openMenu,
  19. close: jpm.closeMenu,
  20. someComplexMethod: function( ) {}
  21. };
  22. };
  23. })(jQuery);

Os métodos e propriedades da API estarão disponíveis através do objeto retornado a partir do momento em que o plugin for inicializado.

  1. var jpm = $.jPanelMenu({
  2. duration: 1000,
  3. });
  4. jpm.open( );

Polindo a interface de desenvolvimento

Com apenas algumas construções simples e linhas de seguimento, construímos um plugin extensível e reutilizável que facilitará as nossas vidas. Como qualquer parte do que fazemos, faça testes com essa estrutura para ver se ela funciona pra você, seu time, e seus métodos de trabalho.

Sempre que percebo que estou construindo algo que poderei reutilizar, divido ele em módulos e transformo em um plugin jQuery. A melhor parte desta prática é que ela o força a utilizar  — e testar — o código que está escrevendo. Utilizando algo que você está desenvolvendo, você notará rapidamente pontos fortes, falhas e mudanças no plano de desenvolvimento.

Esse processo cria um plugin preparado para ser disponibilizado na forma de código aberto (open-source), ou vendido e distribuído. Eu lanço (a grade maioria) meus plugins testados, como projetos open-source no GitHub.

Mesmo que você não esteja construindo algo para ser "dado a natureza", ainda é importante pensar sobre a estrutura do seu código. O seu "eu do futuro" vai agradecer.

---

1. o autor faz um trocadilho entre "design of code" e "design", mas traduzindo, "design of code" seria "estrutura do código" ou "padrão de codificação", portando mantive a ideia do trocadilho, mas a partir de agora tratarei "design" como "estrutura" ou "padrão", dependendo do contexto. (voltar ao texto)

---

Traduzido com autorização de A List Apart e do autor.

Artigo original escrito por Anthony Colangelo.

Acesse o artigo original em A List Apart – "The Design of Code: Organizing JavaScript" – 21de maio de 2013.

---

30 mai
[value]