Organize seu código Javascript de maneira fácil!

js

Ao longo desses anos nesta indústria vital já participei de inúmeros projetos… e foram tantos que os dedos das mãos seriam insuficientes para contá-los. Alguns deles me orgulho, outros nem tanto (afinal como você, eu também já produzi muita coisa de qualidade duvidosa). Ainda assim acredito na máxima que as pessoas sempre evoluem, uma vez que estas buscam sempre o melhor dentro da missão de cada uma.

Organizar código Javascript para quem está iniciando nem sempre é fácil, pois na ótica do programador novato a linguagem é o mesmo que um monte de blocos de código (leia funções) que este foi criando ou até mesmo copiando para resolver os problemas do dia-a-dia. Esse pensamento, somado a inúmeras más práticas vão tornando o código feito com Javascript um tanto que caótico.

Entre as principais (más práticas), eis algumas que a meu ver atrapalham e irritam grande parte dos membros de um time de desenvolvimento (ah e faz a mãe do programador, ser lembrada):

  • falta de indentação
  • falta de comentários
  • variáveis espalhadas
  • variáveis globais
  • funções e variáveis criadas sem propósito

Mas o objetivo deste artigo não é só citar as partes ruins do desenvolvimento, e sim propor uma forma elegante de resolver isso. Então vamos a uma solução simples para organização dos seus códigos feitos com JavaScript.

Funções nomeadas x funções anônimas

Todo mundo aqui, deve saber o que são funções nomeadas e anônimas em JavaScript. Se não sabe, eis alguns exemplos:

// função nomeada
function common() {
    return true;
}

Acima vemos uma função nomeada e, a seguir, uma função anônima:

// função anônima
var anonymous = function() {
 return true;
}

Observando os dois códigos, vê-se pouca diferença, não é mesmo? Os dois quando executados retornam a mesma coisa (true), porém são padrões sintáticos bem distintos.

No primeiro, temos uma função definida com o nome common, e é através desse nome que será possível invocar essa função, desse jeito:

common();
// => true

No segundo, note que a função não possui um nome, então ela precisou ser atribuída a variável anonymous para que pudesse ser invocada. Neste caso a chamada seria idêntica ao exemplo anterior:

anonymous();
// => true

Entendeu o conceito? Em linhas gerais, desculpe a ambiguidade, a função nomeada chama-se assim porque tem um nome. A função anônima, por sua vez não possui um nome, então a única forma de utilizá-la é atribuindo-a algo (uma variável, uma propriedade em um objeto, etc). Perdi esse tempo, explicando isso, pois acho que vai valer a pena para você entender o que vamos fazer a seguir.

Começando a organização

Vamos iniciar os trabalhos, criando uma função anônima:

function() {}

Se você salvar esse código e tentar executá-lo em sua página, ou mesmo rodá-lo no console do seu navegador tomará um SyntaxError. E isso tem um motivo óbvio, pois se a função não tem nome como eu vou chamá-la? Então teoricamente eu seria obrigado a atribui-la a uma variável ou algo do tipo. Neste caso, vamos fazer diferente:

(function() {})

Colocando esse código entre parênteses, o SyntaxError que estava rolando até então sumirá. Mágica? Magia negra? Não! Simplesmente os parênteses agruparam a nossa função, formando uma espécie de expressão. Esse código servirá de embrulho (wrapper) para tudo que vamos fazer daqui pra frente. Farei um pequeno teste agora, colocando um simpático console.log dentro da nossa função e, se tudo der certo, o resultado será a exibição do texto “less is more!”:

(function() {
 console.log("less is more!");
})

Se você executou esse código na sua página, e deu uma olhadinha no console, vai perceber que não houve retorno algum. Ué, o que que houve? Ocorre que apesar de termos uma função que implementa uma única linha de código, ele só está definida, porém não foi executada. Para fazer isso, basta adicionar parênteses no final da expressão, desta forma:

(function() {
 console.log("less is more!");
})();

Bingo! A partir de agora, toda vez que a página for carregada, esse função será executada “automagicamente”! Então temos a base necessária para organização de nossos códigos.

Organizando seu código

Você já deve ter ouvido falar, que toda variável precisa ser declarada usando a palavra chave var. Não usar o var, custa caro, pois uma variável definida sem ele vai parar no escopo global, então para seguir a régua de boas práticas vamos sempre usá-lo.

(function() {
    console.log("less is more!");

    var box = {};

})();

No exemplo acima, defini uma variável box que armazena um objeto vazio. A grande vantagem dessa abordagem é que box não está disponível em nenhum outro escopo a não ser o definido pela função wrapper que fizemos. Então se algum espertinho tentar ir no console e digitar:

console.log(box);
// => ReferenceError: box is not defined

Vai tomar um belo de um ReferenceError no meio da cara! Bom né? Não sujamos o escopo global e ainda ganhamos privacidade! 😀

Uma vez que temos o objeto box, podemos adicionar propriedades e métodos a este objeto. Imagine agora que precisamos criar um controle bem simples, para organizar uma fila com nomes de automóveis. A ideia é começar com a fila vazia, ir adicionando os veículos e retornar a lista no final. Para isso, vamos usar uma propriedade chamada queue e dois métodos, que vamos chamar de addItem e getQueue:

(function() {
    console.log("less is more!");

    // criando o objeto (vazio) box
    var box = {};

    // adicionando a propriedade queue (fila)
    box.queue = [];

    // adicionando o métodos addItem (adicionar item)
    box.addItem = function() {

    };

    // adicionando o métodos getQueue (recuperar fila)
    box.getQueue = function() {

    };
})();

Como podemos perceber, a propriedade queue é um array vazio. Então nosso método addItem precisa receber um veículo como parâmetro e adicioná-lo nesta fila. Por sua vez, o método getQueue apenas retorna uma string com os veículos que temos na fila, separados por um hífen.

(function() {
    console.log("less is more!");

    // criando o objeto (vazio) box
    var box = {};

    // adicionando a propriedade queue (fila)
    box.queue = [];

    // adicionando o métodos addItem (adicionar item)
    box.addItem = function(car) {
        return box.queue.push(car);
    };

    // adicionando o métodos getQueue (recuperar fila)
    box.getQueue = function() {
        return box.queue.join(" - ");
    };
})();

Feito isso, se você rodar esse código, deve estar se perguntando: como diabos vou invocar os métodos addItem e getQueue do objeto box que acabei de implementar, visto que ele não está acessível no escopo global? A resposta é simples, basta fazer com que nossa função wrapper retorne o objeto box (forma simples) ou podemos configurar exatamente o que vai ser retornado. Vamos ao primeiro exemplo:

var GLOBALCAR = (function() {
    console.log("less is more!");

    // criando o objeto (vazio) box
    var box = {};

    // adicionando a propriedade queue (fila)
    box.queue = [];

    // adicionando o métodos addItem (adicionar item)
    box.addItem = function(car) {
        return box.queue.push(car);
    };

    // adicionando o métodos getQueue (recuperar fila)
    box.getQueue = function() {
        return box.queue.join(" - ");
    };

    return box;
})();

Como você deve ter percebido, além de retornar o objeto box, eu atribui o nosso wrapper a uma variável global chamada GLOBALCAR (mesmo com a palavra chave var, como GLOBALCAR não está dentro de uma função, ela fica visível no escopo mais amplo do Javascript, podendo ser acessada de qualquer local). Dessa forma, GLOBALCAR tornou-se um objeto. Para testar nossa implementação podemos executar (eu incentivo você neste momento a testar via console):

GLOBALCAR;
// => Object {queue: Array[0], addItem: function, getQueue: function}

Viu isso? GLOBALCAR é um objeto contendo queue, addItem e getQueue. Então podemos executar o método addItem para adicionar os carros a nossa fila:

GLOBALCAR.addItem("Gol");
// => 1
GLOBALCAR.addItem("Palio");
// => 2
GLOBALCAR.addItem("Corsa");
// => 3

E o método getQueue para retornar os itens que estão na fila:

GLOBALCAR.getQueue();
// => "Gol - Palio - Corsa"

Legal né? Mas ai se você souber um pouquinho mais de JavaScript vai se perguntar porque é possível acessar a propriedade queue diretamente!? Isso tem tudo a ver com a forma que retornamos o objeto box. Se você quiser esconder essa propriedade, deixando disponível apenas os métodos você pode fazer isso:

var GLOBALCAR = (function() {
    console.log("less is more!");

    // criando o objeto (vazio) box
    var box = {};

    // adicionando a propriedade queue (fila)
    box.queue = [];

    // adicionando o métodos addItem (adicionar item)
    box.addItem = function(car) {
        return box.queue.push(car);
    };

    // adicionando o métodos getQueue (recuperar fila)
    box.getQueue = function() {
        return box.queue.join(" - ");
    };

    // retornando um objeto personalizado (só com o necessário)
    return {
        add: box.addItem,
        get: box.getQueue
    };
})();

Agora um novo teste no console revelará:

GLOBALCAR;
// => Object {add: function, get: function}

Note que ninguém, a não ser você saberá da existência da propriedade queue. O mesmo vale para outros métodos que você queira implementar, mais que não fazem sentido serem expostos.

Com base na nova implementação, o método addItem virou apenas add, e o getQueue virou um simples get. Para adicionar itens a nossa fila, usaremos então:

GLOBALCAR.add("Gol");
// => 1
GLOBALCAR.add("Palio");
// => 2
GLOBALCAR.add("Corsa");
// => 3

E para retornar a fila:

GLOBALCAR.get();
// => "Gol - Palio - Corsa"

Elegante não? Agora você já tem uma base sólida para começar a organizar os seus projetos em JavaScript. O mais bacana, é que você pode entender a timeline do processo para chegarmos nesse objetivo. Aproveite o momento de satisfação, e divulge para a galera que agora você aprendeu a usar um pattern para organização do seu código, conhecido por aí como “Module Pattern“. Chique não?

No nosso curso de Programação JavaScript da Caelum, vemos ainda mais boas práticas de organização de JavaScript.

47 Comentários

  1. Eric Douglas 10/03/2014 at 11:16 #

    Excelente artigo Leonardo! Ficaram super didáticos os exemplos!

    Parabéns =)

  2. Thiago 10/03/2014 at 12:13 #

    Faala Léozão muito bom o artigo parabéns !!!

  3. Caio Ribeiro Pereira 10/03/2014 at 13:44 #

    Ótimo artigo! Retweetado! 😀

  4. Italo Veloso 10/03/2014 at 14:35 #

    Artigo sensacional!

  5. Leandro Oriente 10/03/2014 at 14:50 #

    Excelente artigo Léo.

    Parabéns =D

  6. Felipe (@LFeh) 10/03/2014 at 16:56 #

    Excelente.

  7. Mateus Vahl 10/03/2014 at 21:03 #

    Ótimo artigo e exemplos, eu ainda modificaria os métodos addItem e getQueue para retornar a this, assim poderia aplicar o Chain:

    GLOBALCAR.add(“myItem1”).add(“myItem2”).get();

    Não lembro se há algum contra nisso :p

  8. Henrique Silvério 10/03/2014 at 22:27 #

    Uma forma simples, para entender bem o module pattern, que é muito importante em aplicações JavaScript.

    Parabéns pelo artigo, muito bom!

  9. Icaro 11/03/2014 at 08:50 #

    Eu já conhecia e utilizava os recursos indicados, mas gostei por estar bem didático seu post!

  10. Marcos 11/03/2014 at 08:58 #

    Muito legal, ficou simplesmente limpo e funcional.

    Parabéns.

  11. Leonardo Souza 11/03/2014 at 09:19 #

    Obrigado a todos pelo feedback positivo!

  12. Gabriel Zigolis 11/03/2014 at 10:17 #

    Muito legal a sua abordagem Leonardo, bem didática e simples.

    Parabéns!

  13. Renan Reis 11/03/2014 at 11:25 #

    Excelente Leonardo. A explicação mais didática de module pattern que já vi!

    Continue com os posts, existe pouco material didático assim para JS, ainda mais em pt_BR.

    Abração

  14. Eder 11/03/2014 at 14:02 #

    Realmente muito clara sua explicação, parabéns!

  15. Luan 11/03/2014 at 15:04 #

    Muito bom!! 😉 PARABÉNS

  16. Gleison 11/03/2014 at 18:01 #

    Seu artigo ficou fantástico! Didático, fácil e gostoso de ler. Parabéns!

  17. Marcel dos Santos 11/03/2014 at 18:50 #

    Ótimo artigo! Todos os artigos deveriam ter uma didática com esta! Fale mais sobre JavaScript com assuntos que abordem outros patterns, orientação a objetos, testes, promises entre outros.

    Ah, desculpe o preciosismo, mas este é o Revealing Module Pattern (uma pequena variante do Module Pattern)…

    [],

    Marcel

  18. Frederico Maia 11/03/2014 at 20:03 #

    Muito bom mesmo o artigo! Didática excelente.

  19. Marco Ostan 12/03/2014 at 08:22 #

    Muito bom artigo Léo!
    Bastante simples de entender a forma que foi abordado.

  20. Leonardo Souza 12/03/2014 at 08:48 #

    Opa Marcel, sugestões anotadas aqui!

  21. Ronne Clay. 12/03/2014 at 21:07 #

    Show. Magnífico!

  22. Roger 13/03/2014 at 14:06 #

    Show de bola estas dicas, vimos isso em aula.
    Ótimo artigo!

  23. Guilherme Carlos 13/03/2014 at 14:19 #

    Muito bom Leo! Se todos seguissem essas boas práticas facilitaria bastante na hora de dar manutenção naqueles sistemas legados. Gostei bastante do return personalizado, não conhecia essa funcionalidade!

    Abraços

  24. tiago 13/03/2014 at 15:34 #

    Muito bom o post.
    Estava estudando este pattern e ainda não
    tinha me deparado com uma exemplificação tão bem feita.

    Valew

  25. Ney Simões 14/03/2014 at 15:53 #

    Muito bom!!! Parabéns pelo ótimo post continue escrevendo!!

  26. Flávio Almeida 18/03/2014 at 13:42 #

    Oi Leonardo, gostei do tom do post. Só deixar claro que essa solução não resolve o problema de dependências entre scripts. A responsabilidade pela ordem de carregamento ainda é do desenvolvedor.

    Existem bibliotecas que conseguem este grau de encapsulamento e que ainda são capazes de resolver essas dependências. Um
    exemplo é o RequireJS (http://requirejs.org/). Só que ela segue
    o padrão AMD (assyncronous module definition) e se você usa
    Node.js, terá problemas, já que este último utiliza o padrão CommonJS. Há formas de solucionar essa impedância.

    Enfim, quero trazer à luz que além de organizarmos nosso código
    de maneira fácil, também é necessário pensar em como reaproveitá-lo
    tanto no frontend quanto no backend.

    Abraço

  27. Leonardo Souza 18/03/2014 at 13:51 #

    Flávio, acho que não era muito o objetivo deste post falar sobre mecanismos de controle de dependência, mais sem dúvida é um assunto interessantíssimo que pode pode ser explorado em outra pauta aqui no blog.

  28. Diogo Machado 18/03/2014 at 16:39 #

    Muito bom o post Flávio, abriu minha mente quanto as possíbilidades com javascript, achei interessante e ficou bem “orientado a objetos”, isso que gostei muito!

  29. Flávio Almeida 19/03/2014 at 11:57 #

    Oi Leonardo, realmente, tá meio fora do escopo do artigo mesmo. Eu me empolguei aqui! 🙂 Mas como você disse, pode ser mais um post aqui. Abraço!

  30. Daniel 21/03/2014 at 15:31 #

    Meu JavaScript Module Pattern

    https://gist.github.com/danielrohers/9692611

  31. Douglas Rossignolli 03/04/2014 at 11:37 #

    A quase um ano atrás eu fiz essa mesma pergunta no Stackoverflow, e eu mesmo respondi.

    http://stackoverflow.com/questions/11120325/good-practices-on-jquery-gui-development/17351402#17351402

    https://gist.github.com/xdougx/5879172

    Isso sim organiza o seu javascript de forma mais inteligente

  32. Marcus Antonio Sales 03/04/2014 at 12:54 #

    Muito show, uns dos tutoriais mais bem explicado que eu já vi na internet, a partir de hoje vou começa a utilizar em meus projetos.
    Valeu muito obrigado e parabéns.

  33. Jéter Ornelas 03/04/2014 at 13:43 #

    Excelente artigo! Parabéns!

  34. Alessandro Moreira 04/04/2014 at 09:17 #

    Eu realmente ADOREI ! A linguagem fácil, bem explicada, passo a passo, com bom humor e sem tecnismos!

    Parabéns!!

    Espero o próximo.

    PS: Sou de fortaleza e adoro os seus cursos mas infelizmente não resido mas cidades disponibilizadas!!

  35. Carlos Ruesta 04/04/2014 at 16:09 #

    Muito bom Leonardo, parabéns.

  36. Cesar 04/04/2014 at 16:23 #

    Muito bom o tutorial.

  37. Andre 16/04/2014 at 14:06 #

    Ótimo!!!

  38. Danilo Agostinho 19/04/2014 at 00:26 #

    Simples, funcional e prático.

  39. JavaScript Progressivo 15/06/2014 at 00:41 #

    Se todos organizassem seus códigos, o mundo seria um lugar melhor.
    Parabéns pelo artigo.

  40. Luiz H Leme 17/06/2014 at 07:24 #

    Leonardo, excelente artigo.
    Além de complementar o conteúdo de aula, serve como um guia pois está bem explicado com toques Leonardianos para deixar o artigo de fácil entendimento.
    E parafraseando JavaScript Progressivo, se todos organizassem seus códigos não teríamos programadores com traumas de linguagens.

  41. Júnior 07/12/2014 at 16:12 #

    Como fazer para usar um módulo dentro de outro módulo e vice-versa. Como resolver esse problema de módulo ainda não definido?

  42. Adriano 25/02/2015 at 21:35 #

    Clareza! Otima explicacao!

  43. Rafael 15/09/2016 at 11:19 #

    Parabéns! Muito bom!

  44. Ismael da Nóbrega 11/11/2016 at 12:28 #

    Excelente! Estou me desintoxicando de programação imperativa. Este artigo foi muito esclarecedor! Obrigado.reduce();

  45. Danilo 11/01/2017 at 13:42 #

    Pô que artigo massa! Valeu! 🙂

  46. Alan 01/04/2017 at 22:47 #

    Muito bom cara, parabéns!

  47. Silas 02/06/2017 at 08:35 #

    Muito bom, parabéns! Bem didatico.

Deixe uma resposta