BT
x Por favor preencha a pesquisa do InfoQ !

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?

Avalie esse artigo

Relevância
Estilo/Redação

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 mensagens 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 mensagens dessa discussão

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

Receber mensagens dessa discussão

2 Dê sua opinião
Feedback geral
Bugs
Publicidade
Editorial
Marketing
InfoQ Brasil e todo o seu conteúdo: todos os direitos reservados. © 2006-2016 C4Media Inc.
Política de privacidade
BT

Percebemos que você está utilizando um bloqueador de propagandas

Nós entendemos porquê utilizar um bloqueador de propagandas. No entanto, nós precisamos da sua ajuda para manter o InfoQ gratuito. O InfoQ não compartilhará seus dados com nenhum terceiro sem que você autorize. Procuramos trabalhar com anúncios de empresas e produtos que sejam relevantes para nossos leitores. Por favor, considere adicionar o InfoQ como uma exceção no seu bloqueador de propagandas.