BT

CoffeeScript em análise: utilidade, beleza ou ambos?

Postado por Reinaldo Braga em 22 Jun 2011 |

A linguagem CoffeeScript existe desde meados de 2009, e evoluiu bastante desde então, mas o destaque que vem recebendo nos últimos meses é sem precedentes. Tem havido várias discussões acaloradas em torno da linguagem, em grande parte devido a controvérsias em volta da decisão de tornar CoffeeScript a linguagem padrão para scripts no futuro Ruby on Rails 3.1, no lugar do JavaScript, o padrão anterior. Embora a mudança necessária para continuar usando JavaScript no RoR seja pequena, muitos desenvolvedores entraram numa polêmica que evoluiu para algo mais profundo, relacionado a linguagens em geral e ao seu papel no desenvolvimento web. 

Os principais motivos da discussão da utilidade do CoffeeScript envolvem as vantagens técnicas do seu uso e se o ganho é apenas estético. É levantada também a preocupação com o esforço de aprendizado de mais uma linguagem. É importante, entretanto, entender as motivações do uso da linguagem para que se possa tirar uma conclusão mais objetiva.

Origens e Motivação

Para falar de CoffeeScript, precisamos começar com a razão de sua criação. O CS foi criado, segundo seus desenvolvedores, devido ao excesso de verbosidade, além da falta de “elegância” do JavaScript e de outras linguagens hoje usadas para o desenvolvimento na web. 

Como sabemos, o JavaScript se tornou famoso pelo extenso uso em projetos web e, após a Web 2.0 a linguagem se tornou fundamental. Mas apesar de seu alto grau de adoção, a linguagem em si pouco evoluiu. O progresso ocorreu principalmente em volta da linguagem, com a criação de frameworks como jQuery, Prototype e muitos outros. O JavaScript já mostra efeitos da sua idade, se comparado com linguagens com paradigmas mais modernos como Groovy, Python e Ruby (embora algumas destas tenham sido lançadas antes mesmo do JS).

Contudo, com o suporte de JavaScript nos principais browsers e a quantidade de aplicações "legadas", uma atualização da linguagem quebrando a compatibilidade é algo que certamente não vai acontecer tão cedo. É neste ponto que entra o CoffeeScript.

Em vez de se posicionar como um substituto completo ao JavaScript, o CoffeeScript é construído sobre o JavaScript. Programas em CS são "compilados" para JavaScript através de um pré-processador. Os pré-processadores já são usados há décadas, por exemplo em C, com seus #ifdef e #define. Mas a técnica evoluiu muito desde então, sedo utilizada em vários outros contextos, como no framework GWT, em que o código escrito em Java é transformado em JavaScript e HTML; e no SASS, no qual uma "compilação" gera código CSS.

Sintaxe e formas de uso 

A extensão utilizada em arquivos CoffeeScript é .coffee. Os arquivos são compilados para arquivos .js, sendo usados scripts para a compilação. Há instruções específicas no site do CoffeeScript, para instalação do compilador e outras ferramentas. Há ainda extensões que permitem a editores de texto reconhecer a sintaxe e indentação, como vim e gedit.

A seguir, faremos um mergulho na sintaxe da linguagem, por meio de trechos de códigos que destacam as principais diferenças (e semelhanças) entre CS e JS. O leitor notará que o CoffeeScript recebeu inspiração de várias linguagens, especialmente de Ruby e Python.

É possível testar trechos de código em CS no próprio site da linguagem, onde é oferecido um interpretador online acessível através do botão "Try CoffeeScript". Além das saídas dos códigos (se houver), você verá o código JavaScript gerado.

Os exemplos a seguir (baseados em códigos no site do CoffeeScript), começam com o obrigatório "Hello World"; a primeira coluna sempre mostrará o código em CS e a segunda, o código gerado em JavaScript:

CoffeeScript

JavaScript

 
alert "Olá Mundo!"
            
 
alert("Olá Mundo!");
            

Já no "Olá Mundo" vemos algumas diferenças em relação ao JavaScript, por exemplo a ausência do ponto-e-vírgula e os parênteses opcionais, característica também encontrada em Ruby. 

Seguindo com os exemplos, ficarão mais evidentes outras características da linguagem, como a utilização do espaço significativo do Python; ou seja, não são necessários delimitadores de início e de final de blocos, com o contexto sendo demarcado através da indentação. Além disso, o if pode ser usado não só da maneira convencional, mas também no final das expressões, assim como em Ruby.

Atribuições

numero   = 42
oposto = true
 
numeros = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numeros[3..6] = [-3, -4, -5, -6]
 
 
 
              
var numero, oposto, numeros, _ref;
 
numero = 42;
oposto = true;
 
numeros = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
[].splice.apply(numeros, [3, 4]
     .concat(_ref = [-3, -4, -5, -6])),_ref;
              

Observe que não é necessário declarar as variáveis em CoffeeScript; além disso a facilidade para trabalhar com atribuições, inclusive em vetores, é útil em várias situações.

Objetos

math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x
 
 
 
 
            
var math;
math = {
  root: Math.sqrt,
  square: square,
  cube: function(x) {
    return x * square(x);
  }
};
            

Acima, veja como construções mais complexas, como a definição de objetos, ficam mais claras com a simplificação na declaração de funções e atributos. 

Splat (parâmetros variáveis)

corrida = (vencedor, competidores...) ->
  alert competidores
 
corrida "Jose", "Primeiro", "Segundo"
corrida "Joao", "Primeiro", "Segundo", "Terceiro", 
        "Quarto"
 
 
 
 
 
 
 
            
var corrida;
var __slice = Array.prototype.slice;
corrida = function() {
  var competidores, vencedor;
  vencedor = arguments[0], 
          competidores = 2 <= arguments.length 
          ? __slice.call(arguments, 1) 
          : [];
  return alert(competidores);
};
corrida("Jose", "Primeiro", "Segundo");
corrida("Joao", "Primeiro", "Segundo", "Terceiro", 
       "Quarto");
            

Nesse exemplo de utilização do operador splat, fica evidente o quanto de código é economizado e a clareza da construção. 

Condicionais

alert "Eu sabia !" if elvis?
 
numero1 = 1
numero2 = 2
numero3 = 3
numero4 = -4 if oposto
numero5 = 5
 
 
 
 
 
 
 
 
            
var numero1, numero2, numero3, numero4, 
    numero5, numero6, numero7, numero8;
 
if (typeof elvis !== "undefined" &&
    elvis !== null) {
  alert("Eu sabia !");
}
 
numero1 = 1;
numero2 = 2;
numero3 = 3;
if (oposto) {
  numero4 = -4;
}
numero5 = 5;
            

Em casos em que há muitas atribuições, o alinhamento das variáveis e seus valores aumenta a legibilidade. Além disso, se precisamos incluir uma condição isso pode poluir visualmente a sequência. Com a opção de condições no final da linha, esse desconforto é evitado.

Note que as melhorias não são somente estéticas. Por exemplo, no tratamento de existência da variável "elvis" acima, o código JS gerado já trata condições inesperadas para evitar erros em tempo de execução, especialmente erros comuns para usuários inexperientes em JS.

Comprehensions

cubes = (math.cube num for num in list)
 
 
 
 
 
 
 
 
 
 
           
var cubes, num;
 
cubes = (function() {
  var _i, _len, _results;
  _results = [];
  for (_i = 0, _len = list.length; _i < _len; _i++) {
    num = list[_i];
    _results.push(math.cube(num));
  }
  return _results;
})();
            

Estas sentenças "em uma linha" são úteis para operações que são executadas em coleções, simplificando o laço e o controle de condições.

Valores padrão para parâmetros

preencher = (recipiente, liquido = "café") ->
  "Preenchendo o #{recipiente} com #{liquido}..."
 
 
 
 
 
 
            
var preencher;
preencher = function(recipiente, liquido) {
  if (liquido == null) {
    liquido = "café";
  }
  return "Preenchendo o " + recipiente + 
               " com " + liquido + "...";
};
            

Parâmetros opcionais e com valores padrão são úteis para evitar uma cascata de "overloads" muito comum em linguagens estaticamente tipadas. Em JavaScript os parâmetros são opcionais, mas muitas vezes é necesário percorrer a funcão para descobrir qual o valor padrão, caso determinado parâmetro seja omitido. Já com CoffeeScript, isso é explicito.

Interpolação

autor = "Wittgenstein"
citacao  = "Uma foto é um fato. -- #{ autor }"
 
 
sentenca = "#{ 22 / 7 } é uma aproximação de π"
            
var autor, citacao, sentenca;
autor = "Wittgenstein";
citacao = "Uma foto é um fato. -- " + autor;
 
sentenca = "" + (22 / 7) + " é uma aproximação de π";
            

A interpolação é um recurso utilizado para deixar mais clara a concatenação de uma descrição fixa com uma variável. Essa característica da sintaxe do CoffeeScript foi emprestada do Ruby. O conteúdo dentro do operador #{} é avaliado e executado no caso de expressões mais complexas, gerando uma string com a substituição já feita.

Ligação (binding) de funções 

Conta = (cliente, carrinho) ->
  @cliente = cliente
  @carrinho = carrinho
 
  $('.shopping_cart').bind 'click', (event) =>
    @cliente.efetuar_compra @carrinho
 
 
 
 
 
 
 
 
 
 
            
var Conta
var __bind = function(fn, me){ 
                  return function(){ 
                        return fn.apply(me, arguments); 
                                   }; 
                             };
 
Conta = function(cliente, carrinho) {
  this.cliente = cliente;
  this.carrinho = carrinho;
  return $('.shopping_cart')
             .bind('click', 
                 __bind(function(event) {
    return this.cliente.efetuar_compra(this.carrinho);
  }, this));
};
            

A sintaxe para a criação de funções anônimas é muito mais legível, em comparação com o JS. Há duas variações. Com a seta simples, "->", o pré-processador apenas cria a função com os parâmetros determinados; com a seta dupla "=>" é enviado automaticamente o "this" (objeto com o qual a função está ligada).

Os atributos com prefixo @ são uma substituição ao "this", utilizados para que o escopo das variáveis seja apenas no contexto da função, ou seja enviado para outra função no caso de "callbacks". Outro recurso útil é a possibilidade de colocar valores padrão para os parâmetros, deixando bem clara a forma de utilização da função.

Como o código JavaScript gerado pelo tradutor do CoffeeScript é sempre "um-para-um", ou seja para cada instrução CoffeeScript temos uma correspondente em JavaScript, podemos utilizar funcionalidades de biblioteca de terceiros. No exemplo acima (que utiliza JQuery), o pré-processador do CS irá fazer a tradução de maneira correta para o JavaScript, preservando as funcionalidades que temos só no JQuery.

Vigiando o código

É bem comum, ao montar JavaScript, utilizar o arquivo .js separadamente da aplicação para facilitar os testes e ajustes finos, utilizando apenas um arquivo html estático com um trecho de código específico para isso. Com a opção "--watch" do compilador do CoffeeScript, é possível deixá-lo "vigiando" os arquivos .coffee de maneira que, assim que forem alterados, os arquivos .js correspondentes sejam criados evitando passos adicionais – como chamar o compilador manualmente – para esses testes separados da aplicação em arquivos html pontuais.

Conclusões

Examinando alguns exemplos da sintaxe do CoffeeScript, já se pode observar como a linguagem traz os mesmos recursos do JavaScript, de maneira bem mais elegante e clara, exatamente como esperado de linguagens mais modernas.

A legibilidade do código tem sido valorizada cada vez mais. Estudos conhecidos mostram que a manutenção do código representa mais tempo do que sua criação em seu ciclo de vida, e autores como Robert C. Martin (Uncle Bob) em seu famoso livro "Clean Code" mostram técnicas para manter o código limpo e legível. Uncle Bob argumenta que o desenvolvimento de software se compara ao trabalho de artesãos, e defende a preocupação em se criar código legível e compreensível por outros desenvolvedores, e não somente por quem o escreveu.

Além da elegância e clareza, há outros fatores que determinam o uso de uma nova linguagem. Muitos deles não quantificáveis, cabendo à avaliação da equipe, arquiteto ou empresa; outros envolvem preferências pessoais. 

Você escolheria a linguagem CoffeeScript para um novo projeto?

Olá visitante

Você precisa cadastrar-se no InfoQ Brasil ou para enviar comentários. Há muitas vantagens em se cadastrar.

Obtenha o máximo da experiência do InfoQ Brasil.

Dê sua opinião

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber menssagens dessa discussão

Muito legal! by Wander Cleiton da Silva França

Nossa, muito legal essa nova linguagem dinâmica, sua elegância é muito próxima de Ruby e fica realmente mais fácil intender o código, porem, ter que migrar poderá levar tempo, que desenvolvedores não podem se dar. Acredito que tudo dependerá de como ela vai resolver na soluções de problemas e soluções destes, antes de mais nada, não adianta ter uma sintaxe limpa e elegante, mas ser produtiva e eficaz fará total diferença na adoção da nova linguagem.

Bom saber! by Philippe Costa

Muito bom o post. Levando em consideração a legibilidade do código e baixa curva de aprendizagem pra poder utilizar o CoffeeScript eu adotaria sim uma linguagem como essa em projetos futuros. Pelos exemplos que puder ver além de melhor legibilidade, o CS pode seu mais produtivo também.

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber menssagens dessa discussão

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber menssagens dessa discussão

2 Dê sua opinião

Conteúdo educacional

Feedback geral
Bugs
Publicidade
Editorial
InfoQ Brasil e todo o seu conteúdo: todos os direitos reservados. © 2006-2013 C4Media Inc.
Política de privacidade
BT