0% acharam este documento útil (0 voto)
46 visualizações36 páginas

Revista Front-End Magazine - Ed 02

Este documento fornece um resumo das principais características do framework jQuery Mobile, incluindo suporte para múltiplas plataformas, widgets amigáveis para dispositivos móveis, tematização e efeitos. Além disso, explica como criar a primeira aplicação usando este framework e listar os principais recursos como responsividade e navegação entre páginas.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
46 visualizações36 páginas

Revista Front-End Magazine - Ed 02

Este documento fornece um resumo das principais características do framework jQuery Mobile, incluindo suporte para múltiplas plataformas, widgets amigáveis para dispositivos móveis, tematização e efeitos. Além disso, explica como criar a primeira aplicação usando este framework e listar os principais recursos como responsividade e navegação entre páginas.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 36

Assine agora e tenha acesso a

todo o conteúdo da DevMedia:


www.devmedia.com.br/mvp

Edição 02 • 2014

Fale com o Editor!


Atendimento ao leitor
EXPEDIENTE A DevMedia possui uma Central de Atendimento on-line, onde você É muito importante para a equipe saber o que você está achando da revista:
que tipo de artigo você gostaria de ler, que artigo você mais gostou e qual
pode tirar suas dúvidas sobre serviços, enviar críticas e sugestões e
artigo você menos gostou. Fique a vontade para entrar em contato com os
falar com um de nossos atendentes. Através da nossa central também
editores e dar a sua sugestão!
Editor é possível alterar dados cadastrais, consultar o status de assinaturas Se você estiver interessado em publicar um artigo na revista ou no site Java
e conferir a data de envio de suas revistas. Acesse www.devmedia. Magazine, entre em contato com o editor, informando o título e mini-resumo
Diogo Souza (diogosouzac@gmail.com)
com.br/central, ou se preferir entre em contato conosco através do do tema que você gostaria de publicar:
telefone 21 3382-5038.
Consultor Técnico
Daniella Costa (daniella.devmedia@gmail.com) Publicidade Diogo Souza
diogosouzac@gmail.com
publicidade@devmedia.com.br – 21 3382-5038 Analista de Sistemas Java na Indra Company
e já trabalhou em empresas como Instituto
Produção Anúncios – Anunciando nas publicações e nos sites do Grupo DevMedia,
Atlântico e Ebix L.A. É instrutor Android,
palestrante em eventos sobre Java e o mundo
Jornalista Responsável Kaline Dolabella - JP24185 você divulga sua marca ou produto para mais de 100 mil desenvolvedores mobile e consultor DevMedia. Conhecimentos
de todo o Brasil, em mais de 200 cidades. Solicite nossos Media Kits, com e experiências em diversas linguagens e fer-
Capa e Diagramação Romulo Araujo detalhes sobre preços e formatos de anúncios. ramentas de programação e manipulação de
dados, bem como metodologias úteis no de-
senvolvimento de Sistemas diversificados.

Conteúdo sobre Boas Práticas


Sumário
04 – Principais Features do jQuery Mobile
[ Júlio Sampaio ]

Conteúdo sobre Boas Práticas

16 – Programação assíncrona com Node.js


[ Caio Ribeiro ]

Artigo no estilo Curso

26 – Testes unitários em JavaScript: Introdução - Parte 1


[ Sueila Sousa ]
Principais Features do
jQuery Mobile
Conheça todas as principais features do
framework JavaScript mais famoso para
desenvolvimento mobile

A Fique por dentro


experiência com o mundo mobile se torna cada
vez mais aparente e necessária no que se refere
à quantidade de pessoas que usam dispositivos O desenvolvimento de aplicações web tem se mostrado essencial
ou lidam com o universo móvel. No ponto de vista de no universo de programação de uma forma geral. Mais que isso, é
um desenvolvedor, a experiência com o mundo móvel cada vez mais importante saber unir a web ao mundo dos apare-
pode já ter sido vivenciada antes com HTML5, JavaScript lhos móveis, obtendo uma integração rápida, produtiva e eficiente.
ou tecnologias relativas, mas talvez nenhuma delas seja O jQuery Mobile dá um framework do jQuery para desenvolvimento
tão confortável quanto o jQuery é para desenvolver mobile baseado no jQuery original e em JavaScript, que fornece
aplicações para ambientes móveis. Além disso, é uma vários recursos importantes para trabalhar de forma flexível, como
forma um tanto quanto poderosa de criar aplicações web, responsividade, tematização, aplicação de efeitos, etc.
sejam elas para desktop ou móvel, e o jQuery Mobile se Neste artigo veremos de forma prática a maioria dos conceitos bási-
encaixa perfeitamente nesse cenário. cos necessários para entender o que esse framework é capaz de fazer,
O jQuery Mobile foi construído tendo como base a assim como conhecer todos os recursos mais usados do mesmo e como
própria biblioteca JavaScript do jQuery e focando, de eles podem ajudar no desenvolvimento de aplicações reais.
fato, em dar ao desenvolvedor maneiras fáceis de criar
aplicações móveis sem tanto esforço e complexidade
quanto em outras tecnologias. Basicamente, ficará a
cargo do desenvolvedor customizar seu HTML com irá funcionar de forma igual para dispositivos Android, iOS,
arquivos de CSS, e isso rapidamente se transforma num tablets, Blackberry, Windows, etc., até mesmo em plataformas
tormento, especialmente se for necessário tratar de temas em crescimento como a Boot2Gecko e o Tizen. O mesmo código
e estilização como na maioria dos casos. também irá executar normalmente no Chrome, Firefox, Opera,
O framework jQuery Mobile é um framework UI de dentre os diversos tipos de browsers que existem. O interessante é
código fonte aberto e destinado a atender múltiplas saber que esse tipo de tecnologia também terá um funcionamento
plataformas. Ele foi feito usando HTML5, CSS3, além do similar dentre outros tipos de dispositivos, como TV inteligentes,
framework jQuery e de seguir os padrões da Open Web. bem como quaisquer outros que se encaixem nos padrões da web
Ele provê ainda uma porção de widgets amigáveis que aberta. Veja na seção Links a lista completa de browsers certifi-
já são especificamente trabalhados e desenhados para cados suportados, plataformas.
o mundo móvel. Ele tem um poderoso framework para Em algumas plataformas mais antigas, algumas das funcio-
criar temas para estilizar as aplicações. Além disso, su- nalidades, como animações CSS em 3D e Ajax provavelmente
porta Ajax para vários tipos de tarefas, como navegação não serão suportadas, mas com o jQuery Mobile o conceito de
de páginas e transições. “Progressive Enhancement” explicita que funcionalidades básicas
Como o jQuery Mobile segue a linha dos padrões web serão suportadas inicialmente. No futuro, quando browsers e
abertos, você pode ter certeza de que as aplicações terão plataformas se tornarem mais poderosas, as aplicações automa-
o máximo de compatibilidade e suporte dentre a grande ticamente farão uso dessas capacidades e oferecerão suporte de
variedade de browsers e plataformas que existem. É atualização. Na maioria dos cenários, o desenvolvedor não terá
possível, portanto, criar uma aplicação uma vez e ela que escrever código ou interferir de alguma forma. Esse é um

4 Front-end Magazine • Edição 02


grande passo quando comparamos aplicações web com aplicações Criando a primeira aplicação em jQuery Mobile
móveis nativas. Programaticamente falando, o framework requer o uso de
Enquanto escrevendo código para aplicações nativas, será neces- sintaxe (Marcações HTML) para a maioria das tarefas básicas e
sário escrever código em diferentes linguagens, baseado na pla- para construir toda a UI. Você voltar um pouco para os scripts
taforma selecionada. Será necessário também compilar o mesmo JavaScript somente, onde a sintaxe declarativa não ajuda muito e
código para cada plataforma, e construir pacotes binários para logicamente para adicionar a camada lógica. Essa estratégia difere
cada uma delas que possam executar nos dispositivos específicos. um pouco da abordagem usada por outros frameworks, uma vez
Atualizar uma versão da mesma aplicação significar ter de voltar e que a maioria requer muito mais código JavaScript além de ter
refazer todo o exercício de verificar/corrigir o código, reconstruir uma linha de aprendizado mais íngreme.
e reempacotar. E a complexidade pode chegar a níveis bem mais Se você já é familiarizado com HTML, CSS e JavaScript/jQuery,
elevados considerando a quantidade de novas versões geradas. então será muito fácil aprender jQuery Mobile, caso contrário é
Depois de um certo ponto, é provável que o gerenciamento de tal aconselhável dar uma boa estudada sobre esses assuntos antes
versionamento se torne inviável ou relativamente complicado. de prosseguir no artigo.
Claro que existem vantagens em se usar aplicações nativas. Sobre a IDE a ser usada, existem diversas que podem facilitar a
A performance deverá ser um fator crucial a se considerar. Alguns forma de visualização do Drag and Drop assim como o desenvol-
tipos de aplicações necessitam de um tempo de resposta alto, o vimento com o jQuery Mobile por completo. Porém, para iniciar
que leva a considerar código nativo como a melhor saída para tal teu aprendizado, basta utilizar a sua ferramenta editora de texto
situação. Paralelo a isso, através de aplicações nativas é possível favorita. Aqui iremos usar o Notepadd++, que já vem preparado
acessar o núcleo dos Sistemas Operacionais e os recursos dos para fornecer uma lista de recursos poderosos para trabalhar com
dispositivos, como câmeras, calendários, leitores, etc. Coisas que esse tipo de desenvolvimento (veja na seção Links a página oficial
não são facilmente implementadas nos dias de hoje simplesmente do Notepad++). Também será necessário o uso de um browser.
com HTML5.
A HTML5 é um novo mundo que foi apresentado aos desen- Nota
volvedores web front-end. A distância entre essa linguagem e as
Seria interessante se o leitor dispusesse de vários browsers para verificar o funcionamento das
nativas diminui a cada dia, uma vez que uma grande gama de
aplicações construídas aqui, tanto desktop quanto mobile.
recursos semelhantes pode ser implementada e usada a partir de
simples chamadas JavaScript. O framework jQuery Mobile tem
uma lista variada de plugins e ferramentas que podem ajudar a Existem duas formas básicas de usar o jQuery Mobile no seu site.
construir esse tipo de aplicação. Além de ter também uma comu- Ambas envolvem a forma como você irá importar e usar os arqui-
nidade muito ativa e atualizada a todas as constantes mudanças vos js e css da biblioteca. A primeira forma lida com a importação
sofridas pela plataforma. dos arquivos usando CDN (Content Delivery Network), isto é,
Outrossim, as aplicações web tem evoluído. No princípio, elas usando URLs do próprio site do jQuery que nos permitirão fazer
usavam código nativo puro para construir UIs, depois veio a era uso do jQuery Mobile desde que tenhamos uma conexão com a
do Flash e outros plugins UI baseados no mesmo princípio (Como internet. O código da Listagem 1 mostra como fazer isso.
o Silverlight, por exemplo). Porém, essas tecnologias têm seus
dias contados frente ao gigantesco crescimento das tecnologias Listagem 1. Import dos arquivos do jQuery Mobile via CDN
cross-platform, como o jQuery Mobile.
<head>
Mas o que significa dizer que o jQuery Mobile foi feito para <title>jQuery Mobile - Front-end Magazine</title>
mobile? Primeiramente, ele foi otimizado para toques. É comum <link rel=”stylesheet” href=”http://code.jquery.com/mobile/1.4.4/
ver usuários reclamarem de sites que são adaptados do desktop jquery.mobile-1.4.4.css” />
<script type=”text/javascript” src=”http://code.jquery.com/
para o móvel e não conseguirem fornecer sequer um clique de jquery-1.11.0.min.js”></script>
um botão sem falhas, ou certas funcionalidades não ocorrendo da <script type=”text/javascript” src=”http://code.jquery.com/mobile/1.4.4/
forma que acontecem no uso da aplicação através de um browser jquery.mobile-1.4.4.js”></script>
</head>
no computador. O jQuery Mobile se encaixa perfeitamente a este
cenário, uma vez que o mesmo foi criado para se adaptar a todos
os diferentes tamanhos de tela, seja ela a de um smartphone ou É possível ver as importações dos links diretamente dos servido-
de um notebook. Além disso, jQuery Mobile é responsivo. Isso já res do jQuery, e todas dentro da tag HTML <head>. Além disso,
diz muito. Frameworks responsivos que consigam fornecer adap- vale ressaltar que estamos usando as últimas versões disponíveis
tação de telas para ambientes totalmente diferentes são difíceis de no momento de escrita deste artigo. Note também a importação
encontrar, ainda mais fazendo o que se propõem a fazer. Nesse do arquivo JavaScript do jQuery, uma vez que a biblioteca é uma
tipo de cenário, a única preocupação do desenvolvedor é escrever das dependências para uso do jQuery Mobile.
o código uma vez, e deixar com que o jQuery se encarrega dos A segunda forma de se importar é efetuando o download dos
redimensionamentos e demais tarefas. arquivos na origem fisicamente. Basta efetuar o download a partir

Edição 02 • Front-end Magazine 5


Principais Features do jQuery Mobile

dos mesmos links usados na Listagem 1 e adicionar as chamadas • Adicionamos duas novas tags <meta> dentro da tag <head> da
relativas aos diretórios dos mesmos. Para esse tipo de abordagem página que se referem, respectivamente, à definição do encoding
é interessante renomear os arquivos, removendo as versões dos da página para exibição de caracteres especiais (UTF-8), e à defi-
mesmos. Você pode usar essa abordagem quando estiver traba- nição de tamanho que a tela deverá ocupar dentro do dispositivo
lhando em modo offline, ou quando desenvolver uma aplicação que a estiver exibindo;
que não tiver acesso à internet. • A divisão do corpo da página é básica e semelhante à forma
Criemos agora a estrutura básica inicial de diretórios para o como trabalhamos com tabelas (dividida em cabeçalho, corpo e
projeto, sempre dividindo os arquivos em pastas específicas para rodapé). Dessa forma, basta adicionar os elementos data-role às
o mesmo, mantendo, assim, um nível de organização mínima para div’s com seus respectivos valores e a mágica será feito. O jQuery
os projetos (Listagem 2). Mobile irá configurar a página estruturalmente com os elementos
Em seguida, crie a página index.html, tal como demonstrado específicos, bem como aplicará os efeitos e design associados de
na estrutura de diretórios e a preencha com o conteúdo visto na forma automática.
Listagem 1, adicionando também o conteúdo da Listagem 3. Vejamos como a tela ficou no seu browser no final através da
Figura 1.
Listagem 2. Estrutura de diretórios para o projeto

root
js
// Seus arquivos jquery, caso efetue o download dos mesmos
img
css
pages
index.html

Listagem 3. Conteúdo do corpo da página jQuery Inicial

<!DOCTYPE html>
<html>
<head>
<title>jQuery Mobile - Front-end Magazine</title>
<meta charset=”UTF-8”>
<meta name=’viewport’ content=’width=device-width, initial-scale=1’>
<link rel=”stylesheet” href=”http://code.jquery.com/mobile/1.4.4/
jquery.mobile-1.4.4.css” />
<script type=”text/javascript” src=”http://code.jquery.com/
jquery-1.11.0.min.js”></script>
<script type=”text/javascript” src=”http://code.jquery.com/mobile/1.4.4/ Figura 1. Tela de Boas Vindas do jQuery Mobile, redimensionada
jquery.mobile-1.4.4.js”></script>
</head>
<body> Nota
<!-- Página Principal -->
<div id=’main’ data-role=’page’> Atente que todos os elementos têm seu data-role específicos, inclusive o elemento página, que será
<div data-role=’header’> referenciado por data-role=”page”.
<h1>Olá, Seja Bem vindo(a)!</h1>
</div>
<div id=’content’ data-role=’content’>
<p>Introdução ao jQuery</p> Note que, conforme discutimos até aqui, o design responsivo
</div> é característica padrão do jQuery Mobile, tanto que você pode
<div data-role=’footer’> efetuar os testes de responsividade no seu próprio browser, re-
<h4>Revista Front-end Magazine</h4>
</div> dimensionando o mesmo. Além disso, é possível ver a aplicação
</div> do estilo padrão do jQuery Mobile, distribuído nas cores, fontes
</body> e tamanhos que o mesmo utiliza.
</html>

Temas
Com o jQuery Mobile, você também tem em mãos a possibilidade
Note que nesta listagem adicionamos algumas coisas novas. de trabalhar com os skins (temas) criados pela comunidade que
Podemos observar algumas mudanças: estão disponíveis para estilizar suas aplicações de outra forma.
• Adicionamos o elemento simples DOCTYPE no início do docu- Por padrão, o jQuery Mobile disponibiliza cinco temas básicos
mento, isso quer dizer que estamos usando HTML5 por padrão chamados de color swatches (amostra de cores), que são nomeados
na página, não somente refletido nesta declaração em específico, das letras a até a e. Por padrão, o esquema d é usado quando criado
mas também nos demais elementos dentro das páginas; uma página. É possível mudar esse tipo de configuração apenas

6 Front-end Magazine • Edição 02


adicionando um novo atributo aos elementos divisores (div’s), tal da aplicação. O único momento onde a página principal deixará
como na Listagem 4. de existir será quando o usuário navegar para outras páginas,
O resultado pode ser visualizado na Figura 2. que agora serão marcadas como páginas ativas. A exceção da
página principal, todas as outras páginas serão removidas do
DOM quando o usuário sai delas. Isso garante uma navegação
mais otimizada. Por sua vez, a navegação entre as páginas é feita
usando links âncoras. Os âncoras são decorados como botões
usando o atributo data-role=”button”. Clicar num link desses fará
com que a navegação ocorra com algumas transições CSS3, e a
nova página será aberta via Ajax.
Mas antes de prosseguirmos, vamos dar uma olhada na Tabela 1
que traduz exatamente a diferença entre os diferentes e princi-
pais níveis de telas que podemos ter nos templates, a página e o
diálogo.
Vejamos então como colocar ambos conceitos em prática, isto é,
como criar uma página HTML simples com um template que nos
permita navegar entre duas páginas da aplicação.
Dentro da pasta pages crie um novo arquivo HTML e nomeie-o
como “principal.html”. Dentro desse arquivo adicione o conteúdo
da Listagem 5.
Figura 2. Tela de Boas Vindas com tema b aplicado
Listagem 5. Página principal para controle de navegação
Listagem 4. Configurando temas com o jQuery Mobile
<body>
<!-- Página Principal -->
<div id=’main’ data-role=’page’ data-theme=’a’>
<div id=’main’ data-role=’page’ data-theme=’a’>
<div data-role=’header’ data-theme=’b’>
<div data-role=’header’ data-theme=’b’>

<h1>Principal</h1>
<div data-role=’footer’ data-theme=’b’>
</div>
<div id=’content’ data-role=’content’>
<a href=”pagina2.html” data-role=”button”>Ir para Página 2</a>
Templates </div>
<div data-role=’footer’ data-theme=’b’>
Os templates são formações pré-formadas com o intuito de <h4>Rodapé</h4>
facilitar o aproveitamento de esforços, como estruturação e de- </div>
</div>
sign, de modo a aumentar a produtividade dentro de um dado
</body>
framework.
Em uma aplicação que usa um template simples, cada página
da aplicação terá seu próprio arquivo HTML. Uma página será Observe que preservamos o conteúdo das tags de cabeçalho e
sempre envolvida dentro de um container de página definido da página jQuery. Como estamos usando template, não tem pro-
como a div que vimos nos exemplos anteriores. Quando você blema então usar páginas HTML separadas. Isso quer dizer que a
executa a aplicação, o jQuery Mobile irá carregar a primeira pá- chamada à página 2, demonstrada no exemplo irá funcionar. Logo,
gina da aplicação (ou a página principal, main) dentro do DOM, criemos então a página que será redirecionada, nomeando-a de
no qual a referência será mantida durante todo o ciclo de vida “pagina2.html” e adicione o conteúdo da Listagem 6.

Página Diálogo
Um página (ou page) no jQuery Mobile é o objeto básico escrito em conjunto com o
container <div data-role=”page”> que será exibido na tela. Você pode embutir vários
Um diálogo é uma página que tem um atributo data-role=”dialog”. Você
controles HTML5 e widgets dentro de uma página. O framework jQuery Mobile
também pode carregar uma página como um diálogo adicionando o atributo
automaticamente calcula e exibe todos estes controles, fazendo deles amigáveis ao
data-rel=”dialog” ao link da página. O diálogo é estilizado de forma diferente
toque para dispositivos como tal. Sua aplicação pode ter um série de arquivos HTML
à forma como a página ganha seu design, e isso ele também aparece no meio
individuais cada um representando uma simples página, ou ele pode ter um simples
da tela abaixo da página. Ademais, o diálogo também provê um botão para
arquivo HTML contendo múltiplas div’s dentro dele. Você pode fornecer também
fechá-lo no seu cabeçalho.
outros links internos para abrir outras páginas usando Ajax em conjunto com o CSS3.
Dessa forma, conforme vimos até então, as demais páginas serão escondidas.

Tabela 1. Diferenças entre os tipos de telas no jQuery Mobile

Edição 02 • Front-end Magazine 7


Principais Features do jQuery Mobile

Listagem 6. Página secundária a ser chamada pela principal vel, dada a cada vez maior gama de browsers que aderem aos
padrões atuais.
<div id=’main’ data-role=’page’ data-theme=’a’>
<div data-role=’header’ data-theme=’b’>
• Por outro lado, apenas o primeiro carregamento será mais len-
<h1>Principal</h1> to, depois disso todos os demais serão rápidos, uma vez que as
</div> páginas já estão carregadas.
<div id=’content’ data-role=’content’>
<a href=”#” data-role=”button” data-rel=”back”>< Voltar</a>
</div> Listagem 7. Conteúdo da página inicial de multi template
<div data-role=’footer’ data-theme=’b’>
<h4>Rodapé</h4> <div id=”principal” data-role=”page”>
</div> <div data-role=”header”>
</div> <h1>Cabeçalho da #principal</h1>
</div>
<div data-role=”content”>
<a href=”#pagina2” data-role=”button” data-ajax=”false”>Ir página 2</a>
Se não funcionar, pode ser que tenha algum problema de ver- </div>
são relacionado. Dessa forma, basta adicionar o atributo data- <div data-role=”footer”>
<h4>Rodapé da #principal</h4>
ajax=”false” ao mesmo link e o efeito será aplicado normalmente.
</div>
Note também que usamos na segunda página o atributo “data- </div>
rel” com o valor back para efetuar o redirecionamento para a <div id=”pagina2” data-role=”page” data-title=”Template Multi-Página”>
<div data-role=”header”>
página anterior no histórico do browser. Isso também significa <h1>Cabeçalho da #principal</h1>
que se você tiver ambos href e data-rel no mesmo link, o jQuery </div>
Mobile irá ignorar o href e executar apenas o efeito de voltar para <div data-role=”content”>
<a href=”#” data-role=”button” data-rel=”back”>< Voltar</a>
a página anterior. </div>
Quando se trata de templates para múltiplas páginas, o jQuery <div data-role=’footer’ data-theme=’b’>
Mobile necessitará que o arquivo HTML tenha múltiplas páginas <h4>Rodapé</h4>
</div>
dentro dele mesmo. Cada página é encapsulada dentro de uma </div>
página container como uma <div data-role=”page”>. O ID da pá-
gina é usado para identificar as páginas por linking ou invocando
ações nelas. O id da página deve ser único, assim como os demais Diálogos
id’s para os demais componentes. Quando você executar a apli- Para converter uma página em um diálogo é bem simples, bas-
cação, o jQuery Mobile irá carregar todas as páginas disponíveis ta adicionar o atributo data-rel=”dialog” ao link que chamará a
no DOM e exibe a primeira página que ele encontra no HTML. mesma página. Dessa forma, teremos o modo diálogo selecionado.
A navegação entre as páginas é especificada através do mesmo Faça isso para o mesmo exemplo usando o template multipáginas
uso de âncoras visto anteriormente, e você pode personalizar criado e fazendo a modificação devida. O resultado poderá ser
esses links como botões usando o atributo data-role=”button”. observado na Figura 3.
Ao clicar em qualquer link, a navegação ocorre com as mesmas
transições CSS3, e a nova página é então exibida via Ajax. Vejamos
então como fazer isso.
Crie uma nova página HTML e nomeie-a “multi.html” e adicione
o conteúdo da Listagem 7 nela.
Note que agora adicionamos as duas páginas juntas dentro de
um mesmo arquivo HTML. Depois, mudamos as referências para
que o link apontasse agora para o id da div de página 2, ao invés
da página física como fazíamos antes. Dessa forma, temos uma
implementação mais robusta e livre de erros de Ajax e navegação.
O funcionamento será praticamente o mesmo, porém com essa Figura 3. Tela da listagem transformada em Diálogo
diferença imperceptível aos olhos do usuário final.
Em contrapartida, esse tipo de abordagem deve levar em consi- Também é possível personalizar a forma como o diálogo abre,
deração alguns fatores (dentre os quais alguns negativos): através dos efeitos de transição, comuns à maioria dos componen-
• Um template multipáginas será mais pesado em função do tes desse tipo no jQuery. Tente por exemplo adicionar os atributos
crescimento do DOM (Muitas vezes insignificante diante da a seguir e verificar o comportamento do diálogo após:
diminuição de requisições necessárias);
• A aplicação necessitará suporte JavaScript. Isso irá limitar sua data-transition=”slidedown”
escolha de plataformas alvo e você terá que ignorar algumas data-transition=”flip”
plataformas legadas. Mas isso também é algo pouco preocupá-

8 Front-end Magazine • Edição 02


Além disso, você também pode querer alterar certas caracterís- Esse tipo de implementação é muito importante pois é através
ticas gráficas dos componentes do jQuery que vêm de forma pa- dela que muitas mudanças importantes no projeto serão feitas. É
drão, como a posição que o botão de fechar vem posicionado, por preciso conhecer bem o framework para inferir alterações signi-
exemplo (à esquerda). Para tal, você precisará conhecer um pouco ficativas no mesmo, de tal forma que surtam o mesmo efeito an-
mais do CSS do framework, como podemos ver na Listagem 8. terior. Você pode praticar esse tipo de implementação analisando
Crie uma nova página “dialog-customizado.html” e adicione o o código gerado pelo jQuery Mobile em alguma ferramenta de
conteúdo da listagem na mesma. análise e inspeção.

Listagem 8. Estilizando diálogo no jQuery Mobile Transições


Conforme falamos anteriormente, o jQuery Mobile faz uso ex-
<div id=”principal” data-role=”page”>
<div data-role=”header”>
tensivo de CSS3 para aplicar determinados efeitos, dentre estes
<h1>Cabeçalho da #principal</h1> os mais comuns, de transição. A lista de efeitos é limitada, o que
</div> significa que pode não atender todas as necessidades do desenvol-
<div data-role=”content”>
<a href=”#dialogo” data-role=”button” data-rel=”dialog”>Ir página 2</a>
vedor quando da implementação de certas funcionalidades. Por
</div> padrão, os efeitos “fade” são usados para as páginas e o “pop” é
<div data-role=”footer”> usado para os diálogos (você pode encontrar a lista de todos os
<h4>Rodapé da #principal</h4>
</div> efeitos no site oficial do projeto), todavia, você pode querer navegar
</div> entre páginas usando um efeito customizado que funcionará de
<div id=”dialogo” data-role=”page” data-title=”Template Multi-Página”> forma diferente aos padrões do framework.
<div class=”ui-corner-top ui-overlay-shadow ui-header ui-bar-a” role=”banner”>
<a href=”#main” data-icon=”delete” data-iconpos=”notext” Para criar nosso próprio efeito, precisaremos atuar com CSS,
class=”ui-btn-right ui-btn ui-btn-icon-notext ui-btn-corner-all ui- logo crie uma nova página HTML (“efeito-custom.html”) e adi-
shadow ui-btn-up-a”
cione a tag <style> à mesma. Em seguida, adicione o conteúdo da
title=”Fechar” data-theme=”a” data-transition=”pop” data-direction=”reverse”>
<span class=”ui-btn-inner ui-btn-corner-all”> Listagem 9, de forma a prover os recursos básicos para aplicar o
<span class=”ui-btn-text”>Fechar</span> efeito desejado.
<span class=”ui-icon ui-icon-delete ui-icon-shadow”></span>
</span>
</a> Listagem 9. CSS3 para aplicar efeito de salto na página
<h1 class=”ui-title” tabindex=”0” role=”heading” aria-level=”1”>
Diálogo Customizado</h1> .salto.in, .salto.in.reverse {
<div data-role=”content”> -webkit-transform: translateY(0) ;
<a href=”#” data-role=”button” data-rel=”back”>< Voltar</a> -webkit-animation-name: saltoin;
</div> -webkit-animation-duration: 1s;
<div data-role=’footer’ data-theme=’b’> -webkit-animation-timing: cubic-bezier(0.1, 0.2, 0.8, 0.9);
<h4>Rodapé</h4> }
</div> @-webkit-keyframes saltoin {
</div> 0% { -webkit-transform: translateY(100%); }
</div> 90% { -webkit-transform: translateY(-10%); }
100% {-webkit-transform: translateY(0); }
}
Repare que mantivemos a estrutura final das páginas que ví- .salto.out, .salto.out.reverse {
-webkit-transform: translateY(100%);
nhamos criando até então, porém a estruturação muda um pouco, -webkit-animation-name: saltoout;
uma vez que desejamos assemelhar a implementação à criada -webkit-animation-duration: 1s;
-webkit-animation-timing: cubic-bezier(0.1, 0.2, 0.8, 0.9);
pelo jQuery Mobile por padrão. As mudanças consistirão basica-
}
mente em analisar o HTML gerado pelo framework e substituir @-webkit-keyframes saltoout {
determinadas classes CSS, como a classe “ui-btn-right” em vez da 0% { -webkit-transform: translateY(0); }
90% { -webkit-transform: translateY(110%); }
“ui-btn-left”, o que fará com que o componente botão se alinha à
100% {-webkit-transform: translateY(100%); }
direita. O resultado pode ser verificado na Figura 4. }

Além disso, para o efeito funcionar, adicione o atributo data-


transition=”salto” ao link. Note que o efeito aplicado será de
uma espécie de salto na página tanto indo quanto voltando na
mesma.
Também podemos usar JavaScript para aplicar efeitos nas pá-
ginas do jQuery Mobile. Por exemplo, criemos na mesma página
do exemplo anterior uma nova tag <script> dentro da própria tag
Figura 4. Tela de diálogo customizado com botão à direita <head> e adicionemos o código contido na Listagem 10.

Edição 02 • Front-end Magazine 9


Principais Features do jQuery Mobile

Listagem 10. Exemplo de função JavaScript para criar efeito de transição Mobile surjam com novas regras de transição e acabem quebrando
as suas customizadas.
<script type=”text/javascript”>
function transicaoCustomizada(nome, reverso, $para, $de) {
var diferido = new $.Deferred(); Componentes e Widgets
// Define a animação customizada
$para.width(“0”);
$para.height(“0”);
Toolbar
$para.show(); No jQuery Mobile existem duas toolbars (barra de ferramentas)
$de.animate({ width: “0”, height: “0”, opacity: “0” }, básicas, o Header (Cabeçalho) e o Footer (Rodapé). Até agora já
{ duration: 750 },
{ easing: ‘easein’ }
abordamos os dois nos exemplos utilizados, mas onde e para o que
); eles podem ser usados? O que o jQuery consegue abordar a mais
$para.animate({ width: “100%”, height: “100%”, opacity: “1” }, em relação a essas áreas? O header basicamente sempre exibe o
{ duration: 750 },
{ easing: ‘easein’ } nome da página, o título do cabeçalho, mas pode ser usado para
); controlar também a navegação através do navbar. O footer pode
// Padroniza o template do jQuery Mobile ser usado para várias coisas, tais como incluir botões e formulários
classeReversa = reverso ? “ reverso” : “”;
classeView = “ui-mobile-viewport-transitioning viewport-” + nome; de controle e pode ser customizado para as necessidades mais
$para.add($de).removeClass(“out in reverso “ + nome); específicas. Ele pode ser usado como controle de navegação tam-
if ( $de && $de[0] !== $para[0] ) { bém, assim como para exibir informações relacionadas à empresa,
$de.removeClass($.mobile.classePaginaAtiva);
} copyright, etc.
$para.parent().removeClass(classeView); Vejamos o código presente na Listagem 11. Ele exemplifica um
diferido.resolve(nome, reverso, $para, $de);
bom uso da toolbar para controlar a navegação de páginas.
$para.parent().addClass(classeView );
if ($de) {
$de.addClass(nome + “ out” + classeReversa);
} Listagem 11. Exemplo de função JavaScript para criar efeito de transição
$para.addClass($.mobile.classePaginaAtiva + “ “ + nome + “ in” + classeReversa);
return diferido.promise(); <div id=”principal” data-role=”page”>
} <div data-role=”header”>
// Registra a transição customizada <h1>Galeira de Fotos</h1>
$.mobile.transitionHandlers[“slide-sumir”] = transicaoCustomizada; </div>
</script> <div data-role=”content”>
<img src=”../img/logo-devmedia.png” />
<br>DevMedia - Cursos e Treinamentos Online
<br><a href=”#photo” data-role=”button” data-inline=”true”>
Além disso, altere também o atributo data-transition para o View full screen</a>
</div>
novo valor: slide-sumir. Após o teste, você verificará que o efeito <div data-role=”footer”>
mudou para uma mistura de slide para a esquerda/direita com <h4>Rodapé da Galeria</h4>
um efeito de sumiço. Todo esse processo foi possível graças à </div>
</div>
sobrescrita do objeto Deferred, com a configuração da altura <div id=”photo” data-role=”page” data-fullscreen=
e largura do mesmo, possibilitando que as mesmas pudessem ”true” data-add-back-btn=”true”>
ser aplicadas ao efeito de animação em conjunto com a função <div data-role=”header” data-position=”fixed” >
<h1>DevMedia - Cursos e Treinamentos Online</h1>
show() do próprio jQuery. Note que as configurações de duração </div>
das animações são essenciais para definir o escopo do efeito, este <div data-role=”content”>
<img src=”../img/logo-devmedia.png” width=”60%”
que pode ser alterado à vontade pelo desenvolvedor de forma a
style=”padding: 120px; margin: 0 auto;”/>
alcançar maiores níveis de personalização. </div>
Uma vez terminada a transição, o código deve garantir que a <div data-role=”footer” data-position=”fixed”>
Data: 10/10/2010
página correta esteja ativa. Logo após, é necessário chamar a
</div>
função diferido.resolve() e retornar a função promise(). Final- </div>
mente, é importante registrar a transição customizada de forma
a poder associá-la ao atributo jQuery correspondente. A função
transitionHandlers() se encarregará disso. O que fizemos foi basicamente simular uma galeria de fotos, com
Não existe nenhuma regra básica que defina qual das duas uma imagem apenas (verifique os arquivos de download ou use
implementações é melhor, isso vai depender da forma como você qualquer imagem). Criamos uma página simples, com navegação
está trabalhando baseada nos padrões do projeto e/ou restrições multi-página, nenhuma novidade. Detalhes são os novos atributos
de clientes. Usar CSS3 é mais intuitivo e fácil para a maioria usados na página referente à imagem em tamanho aumentado,
dos profissionais que trabalham com web, além de mais fácil de que conta com atributos como data-add-back-btn, que concede à
manter e não requerer conhecimentos de lógica de programação. div a função de controladora de navegação. Além disso, na segun-
Além disso, é provável que no futuro novas versões do jQuery da tela é possível analisar a visualização do rodapé somente no

10 Front-end Magazine • Edição 02


Figura 5. Telas de representação do uso da toolbar como galeria de fotos

final da página, conferindo um ar de aplicação mais trabalhada, ao Listagem 12. Footer personalizado para exemplo da Listagem 11
contrário do padrão que é sempre exibir o footer ao final de cada
<div data-role=”footer” data-position=”fixed” class=”ui-bar”>
página e seu respectivo conteúdo. Veja na Figura 5 o resultado
<fieldset class=”ui-grid-a”>
do exemplo da Listagem 11. <div class=”ui-block-a” data-role=”fieldcontain”>
Vários são os tipos de implementação possíveis com a toolbar, <label for=”notaSlider”>Que nota você dá (1-10)?</label>
desde a implementação de tabulação dando efeitos mais divisórios <input type=”range” name=”notaSlider” id=”notaSlider” value=”5”
min=”1” max=”10”/>
às telas, até a criação de cabeçalhos customizados com a inclusão
</div>
de botões de controle, personalização de cores, CSS, imagens, etc. <div class=”ui-block-b”>
E em relação ao rodapé, pode ser customizado de igual forma. <div data-role=”fieldcontain”>
Basta substituir a div de footer da Listagem 11 pelo conteúdo <fieldset data-role=”controlgroup” data-type=”horizontal”>
<legend>Compartilhe:</legend>
ilustrado na Listagem 12 e teremos um rodapé totalmente per-
<input type=”radio” name=”arquivoCompartilhado”
sonalizado. id=”arquivoCompartilhadoNinguem”
Veja o resultado ilustrado na Figura 6. value=”arquivoCompartilhado-1” checked=”checked” data-theme=”c”/>
<label for=”arquivoCompartilhadoNinguem”>Ninguém</label>
<input type=”radio” name=”arquivoCompartilhado”
id=”arquivoCompartilhadoAmigos”
value=”arquivoCompartilhado-2” data-theme=”c”/>
<label for=”arquivoCompartilhadoAmigos”>Amigos</label>
<input type=”radio” name=”arquivoCompartilhado”
id=”arquivoCompartilhadoPublico”
value=”arquivoCompartilhado-3” data-theme=”c”/>
<label for=”arquivoCompartilhadoPublico”>Público</label>
</fieldset>
</div>
</div>
</fieldset>
</div>

Figura 6. Resultado de footer personalizado na primeira coluna tem como classe a ui-block-a que define que
esse conteúdo deve estar posicionado na primeira coluna.
Essa implementação já trouxe mais novidades sobre o uso de Para criar o slider basta criar um input de formulário comum e
toolbar. A classe ui-bar, adicionada à div footer, já nos informa tipá-lo como “range”, informando seus limites nos atributos min
que faremos configurações além das já padrões existentes, possi- e max. Finalmente, para criar os botões de seleção toggle, basta
bilitando a adição de controles à mesma. Em seguida, adicionamos criar um fieldset com o data-role configurado para controlgroup e
a classe ui-grid-a que nos habilita a usar um fieldset com um inputs para cada uma das opções, não esquecendo de referenciá-
layout de duas colunas. A div container com a role fieldcontain las com o mesmo atributo name.

Edição 02 • Front-end Magazine 11


Principais Features do jQuery Mobile

Botões Formulários
Existe uma infinidade de ações que podem ser efetuadas dentro A tag comum da HTML, <form>, usada para lidar com a comuni-
de uma aplicação, assim como a necessidade de se criar os mais cação HTTP da sua aplicação dinâmica é totalmente encapsulada
diversos tipos de botões que atendam a tais comandos. O jQuery pelo jQuery Mobile de forma a torná-la amigável ao toque e execu-
Mobile possibilita o uso dos elementos botões como links, contro- tar em diversos dispositivos de forma responsiva. Um formulário
ladores de navegação, listas, controladores de formulários, dentre pode ter múltiplos controles listados por padrão verticalmente e
outros. Além disso, várias são as formas que podem ser exibidos, você pode agrupá-los usando um fieldset com o data-role setado
dentro dos limites de estilo estipulados pelo framework. para controlgroup, conforme demonstrado anteriormente. Além
Vejamos o exemplo demonstrado na Listagem 13, bem como disso, ainda pode contar com todo o poder do Ajax para fazer
seu resultado na Figura 7. todo o processo de comunicação com o servidor.
Substitua o conteúdo da div content pelo apresentado na Mas talvez uma das funcionalidades mais interessantes desse
Listagem. O data-role=collapsible possibilita facilmente a criação tipo de recurso seja a facilidade de validar formulários usando o
de listas selecionáveis e em efeito sanfona. Ao fazer uso desse re- próprio jQuery Mobile. Em conjunto com a HTML5 ele consegue
curso, os ícones de mais/menos são automaticamente importados se valer de validações padrão de página, assim como criar suas
pelo jQuery. próprias. Dê uma olhada na Listagem 14.

Listagem 14. Formulário exemplo para validação de campos

...
<script type=”text/javascript”>
$(document).ready(function() {
$(‘#form’).submit(function() {
var len = $(‘#comentario’).val().length;
if ( len < 10 || len > 100 ) {
$(‘#erro’).text(‘Comentário com tamanho inválido!’).show().fadeOut(5000);
return false;
} else
return true;
});
});
</script>
</head>
<body>
<!-- Página Principal -->
<div id=”principal” data-role=”page”>
<div data-role=”header”>
<h1>Cabeçalho</h1>
</div>
<div data-role=”content”>
<form id=’form’ action=’#’ method=’post’>
<div data-role=’fieldcontain’>
Figura 7. Exemplo de lista em efeito sanfona <label for=’nome’>Nome</label>
<input id=’nome’ name=’nome’ type=’text’ required placeholder=
’Digite seu Nome’ />
Listagem 13. Exemplo de uso de botões como listas de seleção no jQuery Mobile </div>
<div data-role=’fieldcontain’>
<div data-role=”content”> <label for=’email’>Email</label>
<div data-role=”collapsible” data-collapsed=”false” data-theme=”a” <input id=’email’ name=’email’ type=’email’ required placeholder=
data-content-theme=”a”> ’Digite seu Email’ />
<h3>Cabeçalho #1</h3> </div>
Corpo #1 <div data-role=’fieldcontain’>
</div> <label for=’comentario’>Comentários</label>
<div id=”collapser” data-role=”collapsible” data-collapsed=”false” <textarea id=’comentario’ name=’comentario’ required
data-theme=”b” placeholder=’Digite seus comentários <Mínimo 10/Máximo 50>’></textarea>
data-content-theme=”b”> </div>
<h3>Cabeçalho #2</h3> <div id=’erro’ style=’color: #f00’></div>
Corpo #2 <input type=’submit’ data-transition=’pop’ value=’Enviar’/>
</div> </form>
<div id=”collapser” data-role=”collapsible” data-collapsed=”true” data-theme=”e” </div>
data-content-theme=”e”> <div data-role=”footer”>
<h3>Cabeçalho #3</h3> <h4>Rodapé</h4>
Corpo #3 </div>
</div> </div>
</div> </body>

12 Front-end Magazine • Edição 02


Observe que a criação do formulário já atende a algumas especi- Listagem 15. Exemplo de formulário com valores pré-selecionados
ficações padrão de HTML5 e outros tipos de formulário, fazendo
<script type=”text/javascript”>
uso do recurso de placeholder, campos obrigatórios, etc. A única
$(document).ready(function() {
novidade está nos data-role do fieldset e nos campos de input do $(‘#selectid’).selectmenu({
formulário (Figura 8). Atente também para o uso das funções com o theme: ‘d’,
inline: false,
jQuery para lidar com os valores dos campos. Nesse tipo de cenário,
corners: true,
o uso do jQuery pode ser feito de igual para o mundo web. icon: ‘star’,
Um outro tipo de implementação bem comum para esse tipo iconpos: ‘left’,
shadow: true,
de recurso de formulário é iniciar um dado formulário com uma
iconshadow: true});
lista de opções já selecionadas, como os valores de um campo de });
select no formulário. Vejamos a Listagem 15. });
</script>
O resultado pode ser visualizado na Figura 9. Perceba as mu-
</head>
danças feitas no atributo data-placeholder, bem como as opções <body>
visíveis pelos elementos opt1 e opt2, além dos grupos criados para <!-- Página Principal -->
<div id=”principal” data-role=”page”>
facilitar a associação de elementos.
<div data-role=”header”>
<h1>Cabeçalho</h1>
</div>
<div data-role=”content”>
<form action=’#’ method=’post’>
<div data-role=’fieldcontain’>
<label for=’selectid’ class=’select’>Menu de Seleção Básico</label>
<select name=’selectid’ id=’selectid’ multiple data-native-menu=’false’
data-overlay-theme=’e’>
<option value=’Menu de Seleção Básico’ data-placeholder=’true’>
Menu de Seleção Básico</option>
<option value=’opt1’>Opção 1</option>
<option value=’disabledopt’ disabled>Opção Disabilitada</option>
<option value=’opt2’>Option 2</option>
<optgroup label=’Opções no Grupo1’>
<option value=’grp1’>&nbsp;&nbsp;&nbsp;&nbsp;Group Opção1</option>
<option value=’grp2’>&nbsp;&nbsp;&nbsp;&nbsp;Group Opção2</option>
</optgroup>
<optgroup label=’Opções no GrupoA’>
<option value=’grpA’>&nbsp;&nbsp;&nbsp;&nbsp;Group OpçãoA</option>
<option value=’grpB’>&nbsp;&nbsp;&nbsp;&nbsp;Group OpçãoB</option>
</optgroup>
Figura 8. Resultado da validação do campo de Comentários </select>
</div>
</form>
</div>
<div data-role=”footer”>
<h4>Rodapé</h4>
</div>
</div>
</body>

Página de Loading
Por padrão, o jQuery Mobile exibe uma animação com o tema a
sem nenhum texto quando tenta carregar uma página. Se aconte-
cer quaisquer erros no meio do caminho, então a página para de
processar e uma mensagem “Error Loading Page” é exibida com
o tema e. Com o jQuery Mobile, é possível, com poucas linhas
de código, sobrescrever as chamadas padrão, por um conjunto
de status preestabelecidos que podem controlar as mensagens a
serem exibidas no lado cliente. Veja na Listagem 16.

Temas
O framework jQuery Mobile provê um sistema leve para tema-
Figura 9. Página de formulário exemplo com campos selecionados tizar componentes, que suporta muitas propriedades CSS3, como

Edição 02 • Front-end Magazine 13


Principais Features do jQuery Mobile

Figura 10. Página do ThemeRoller para criação de temas

bordas redondas, sombreamento e gradientes. Ele também fornece


uma lista de ícones que você pode usar em suas aplicações móveis. adequada dos recursos usados, dadas as frequentes atualizações
Além disso, você pode se valer das amostras e temas já existentes sofridas pelas bibliotecas ante à comunidade desenvolvedora.
no jQuery Mobile. Você também pode usar o site ThemeRoller Ainda teremos muito a melhorar nesse framework, principal-
(seção Links) para criar seus próprios temas (Figura 10), de modo mente relacionado aos estilos muito característicos, mas hoje o
a ter ainda mais flexibilidade na hora de montar o escopo da sua jQuery Mobile se prova de extrema valia para quem desenvolve
aplicação. para a web.

Listagem 16. Exemplo de sobrescrita das mensagens de erro e loading Autor


$(document).ready(function() { Júlio Sampaio
$(document).bind(“mobileinit”, function() { Analista de sistema e entusiasta da área de Tecnologia da Infor-
$.mobile.loadingMessage = “Carregando...”; mação. Atualmente é consultor na empresa Visagio, trabalhan-
$.mobile.loadingMessageTextVisible = true;
$.mobile.loadingMessageTheme = “b”;
do em projetos de desenvolvimento de sistemas estratégicos,
$.mobile.pageLoadErrorMessage = “Desculpa, aconteceu um problema!”; é também instrutor JAVA. Possui conhecimentos e experiência em áreas
$.mobile.pageLoadErrorMessageTheme = “b”; como Engenharia de Software e Gerenciamento de Projetos, tem também
}); interesse por tecnologias relacionadas ao front-end web.
});

Links:
Existem muitas outras features acerca do jQuery Mobile que
não serão cobertas aqui, até mesmo para não fugir do foco, que Lista de dispositivos e plataformas suportados pelo jQuery Mobile
é de fato apresentar a tecnologia aos que ainda não conhecem www.jquerymobile.com/gbs/
o poder que ela fornece ao desenvolvimento de aplicações web
Página oficial do Notepad++
mobile. O jQuery Mobile nasceu com o intuito de unir o poder do
www.notepad-plus-plus.org/
já famoso framework JavaScript, o jQuery, ao recente e cada vez
mais requisitado mundo web mobile, de forma a fornecer suporte, Site do ThemeRoller jQuery Mobile.
componentes de fácil uso e modificação, além de uma manutenção www.themeroller.jquerymobile.com/

14 Front-end Magazine • Edição 02


Edição 02 • Front-end Magazine 15
Programação assíncrona
com Node.js
Boas práticas de programação assíncrona com
JavaScript server-side

T Fique por dentro


udo na web se trata de consumismo e produção
de conteúdo. Ler ou escrever blogs, assistir ou en-
viar vídeos, ver ou publicar fotos, ouvir músicas Quando se trata de desenvolvimento front-end, o Node.js é dis-
e assim por diante. Isso fazemos naturalmente todos os parado uma das tecnologias que mais intrigam e impressionam a
dias na internet. E cada vez mais aumenta a necessidade comunidade de desenvolvimento, por suas várias características
dessa interação entre os usuários com os diversos servi- fundamentais, como poder usar JavaScript no servidor, bem como
ços da web. De fato, o mundo inteiro quer interagir mais o papel que ele exerce nessa comunicação. Para o leitor que já está
e mais na internet, seja através de conversas com amigos familiarizado com JavaScript, Node.js é só mais um curto passo ao
em chats, jogando games online, atualizando constan- aprendizado. Neste artigo veremos desde conceitos de configuração,
temente suas redes sociais ou participando de sistemas ambiente, características, posicionamento atual, até o as vantagens da
colaborativos. Esses tipos de aplicações requerem um po- programação assíncrona, foco central que discute como implementar
der de processamento extremamente veloz para que seja um bom código que evite a criação do famoso anti-patter callback-
eficaz a interação em tempo real entre cliente e servidor. hell do JavaScript.
E mais, isto precisa acontecer em uma escala massiva,
suportando de centenas a milhões de usuários.
Então o que nós, desenvolvedores, precisamos fazer? característica em comum: eles paralisam um processamento
Precisamos criar uma comunicação em tempo real entre enquanto utilizam um I/O no servidor. Essa paralisação é co-
cliente e servidor — que seja rápida, atenda muitos usu- nhecida como modelo blocking-thread. Para entender melhor esse
ários ao mesmo tempo e utilize recursos de I/O (dispo- conceito, vamos a um exemplo: temos uma aplicação web e nela
sitivos de entrada e saída) de forma eficiente. Qualquer cada processo é uma requisição feita pelo usuário. Com o decorrer
pessoa com experiência em desenvolvimento web sabe da aplicação, novos usuários irão acessá-la, gerando múltiplos
que a versão atual do HTTP 1.1 não foi projetada para processos no servidor. Um sistema de arquitetura bloqueante vai
suportar tais requisitos. E pior, infelizmente existem enfileirar cada requisição que são realizadas ao mesmo tempo e
aplicações que adotam de forma incorreta o uso deste depois ele vai processando, uma a uma. Este modelo não permi-
protocolo, implementando soluções workaround (“Gam- te múltiplos processamentos ao mesmo tempo. Enquanto uma
biarras”) que requisitam constantemente o servidor de requisição é processada, as demais ficam em espera, ou seja, a
forma assíncrona, geralmente aplicando a técnica de aplicação bloqueia os demais processos de fazer I/O no servidor,
long-polling. Para sistemas trabalharem em tempo real, mantendo-os em um pequeno período de tempo numa fila de
servidores precisam enviar e receber dados utilizando requisições ociosas.
comunicação bidirecional, ao invés de utilizar inten- Esta é uma arquitetura clássica, existente em diversos sistemas
samente request/response do HTTP aplicando Ajax. E web e que possui um design ineficiente. É gasta grande parte do
também temos que manter esse tipo comunicação de tempo mantendo requisições em uma fila ociosa enquanto é exe-
forma leve e rápida para permitir escalabilidade em cutado I/O para apenas uma requisição. Para exemplificar melhor,
uma aplicação. tarefas de I/O são tarefas de enviar e-mail, consultar o banco de
dados, leitura de arquivos em disco. E essas tarefas bloqueiam
O problema das arquiteturas bloqueantes o sistema inteiro enquanto não são finalizadas. Com o aumento
Os sistemas para web desenvolvidos sobre plataformas de usuários acessando o sistema, a frequência de gargalos será
como .NET, Java, PHP, Ruby ou Python possuem uma maior, surgindo a necessidade de se fazer uma escalabilidade

16 Front-end Magazine • Edição 02


vertical (upgrade dos servidores) ou escalabilidade horizontal O Event-Loop é o agente responsável por escutar e emitir eventos.
(inclusão de novos servidores trabalhando para um load balancer). Na prática, ele é basicamente um loop infinito que a cada iteração
Ambos os tipos se tornam custosos, quando se fala em gastos com verifica em sua fila de listening de eventos se um determinado
infraestrutura. O ideal seria buscar novas tecnologias que façam evento foi disparado. Quando ocorre, é emitido um evento. Ele o
bom uso dos servidores existentes, que permitam o uso intenso executa e envia para fila de executados. Quando um evento está
e máximo do processamento atual. em execução, nós podemos programar qualquer lógica dentro dele
Foi baseado neste problema que, no final de 2009, Ryan Dahl, e e isso tudo acontece graças ao mecanismo de callback de função
mais 14 colaboradores, criaram o Node.js. Esta tecnologia possui do JavaScript.
um modelo inovador: sua arquitetura é totalmente non-blocking Esta técnica que permite trabalhar em cima do design event-
thread (não-bloqueante) que apresenta uma boa performance com driven com Node.js. Ele foi inspirado pelos frameworks Event
consumo de memória e utiliza ao máximo e de forma eficiente o Machine do Ruby e Twisted do Python. Porém, o Event-loop do
poder de processamento dos servidores, principalmente em sis- Node.js é mais performático por que seu mecanismo é nativamente
temas que produzem uma alta carga de processamento. Sistemas executado de forma não-bloqueante. Isso faz dele um grande dife-
criados com Node.js estão livres de aguardarem por muito tempo rencial em relação aos seus concorrentes que realizam chamadas
o resultado de seus processos, e mais importante, não sofrem bloqueantes para iniciar seus respectivos loops de eventos.
dead-locks, pelo simples fato de trabalharem em single-thread. Além
dessas vantagens, desenvolver sistemas nessa plataforma é super Por que deve-se aprender Node.js?
simples e prático. • JavaScript everywhere: Praticamente o Node.js usa JavaScript
O Node.js é uma plataforma altamente escalável e de baixo nível, como linguagem de programação server-side. Essa característica
logo, você terá a possibilidade de programar diretamente com permite que você reduza e muito sua curva de aprendizado, afinal
diversos protocolos de rede e internet ou utilizar bibliotecas que a linguagem é a mesma do JavaScript client-side, seu desafio nesta
acessam recursos do sistema operacional. Para programar em plataforma será de aprender a fundo como funciona a programação
Node.js basta dominar a linguagem JavaScript. Ele utiliza a engine assíncrona para se tirar maior proveito dessa técnica em sua apli-
Javascript V8, a mesma utilizada no navegador Google Chrome. cação. Outra vantagem de se trabalhar com JavaScript é que você
poderá manter um projeto de fácil manutenção. Você terá facilidade
Características do Node.js em procurar profissionais para seus projetos, e vai gastar menos
tempo estudando uma nova linguagem server-side. Uma vantagem
Single-thread técnica do JavaScript comparador com outras linguagens de back-end
Suas aplicações serão single-thread, ou seja, cada aplicação terá é que você não irá utilizar mais aqueles frameworks de serialização
instância de uma única thread por processo iniciado. Se você de objetos JSON (JavaScript Object Notation), afinal o JSON client-side
está acostumado a trabalhar com programação multithread, por é o mesmo no server-side, há também casos de aplicações usando
exemplo, Java ou .NET, infelizmente não será possível com Node banco de dados orientado a documentos (por exemplo: MongoDB ou
.js, mas saiba que existem outras maneiras de se criar um sistema CouchDB) e neste caso toda manipulação dos dados são realizadas
que com processamento paralelo. Por exemplo, você pode utilizar através de objetos JSON também.
uma biblioteca nativa chamada de clusters, que é um módulo que • Comunidade ativa: Esse é um dos pontos mais fortes do Node
permite implementar uma rede de processos de sua aplicação, .js. Atualmente existem várias comunidades no mundo inteiro
você cria N processos de sua aplicação e uma delas se encarrega trabalhando muito para esta plataforma, seja divulgando posts e
de balancear a carga, permitindo processamentos paralelos um tutoriais, palestrando em eventos e principalmente publicando e
único servidor. Outra maneira é adotar a programação assíncrona mantendo +70000 módulos no site NPM (Node Package Manager).
nas tarefas se seu servidor. Aqui no Brasil temos dois grupos bem ativos no Google Groups
Esse será o assunto mais abordado durante o decorrer deste temos o NodeBR e no Facebook tem o grupo Node.js Brasil (ver
artigo, pelo qual explicaremos diversos cenários e exemplos prá- seção Links).
ticos de como são executadas em paralelo, funções em assíncronas • Ótimos salários: Desenvolvedores Node.js geralmente recebem
não-bloqueante. bons salários. Isso ocorre pelo fato de que infelizmente no Brasil
ainda existem poucas empresas adotando essa tecnologia. Isso
Event-Loop faz com que empresas que necessitem dessa tecnologia paguem
Node.js é orientado a eventos. Ele segue a mesma filosofia de salários na média ou acima da média para manterem esses de-
orientação de eventos do JavaScript de browser; a única diferença senvolvedores em seus projetos. Outro caso interessante são as
são os eventos, ou seja, não existem eventos de click do mouse, empresas que contratam estagiários ou programadores juniores
keyup do teclado ou qualquer evento de componentes do HTML. que tenham ao menos conhecimentos básicos de JavaScript, com
Na verdade, trabalhamos com eventos de I/O como, por exemplo, o objetivo de treiná-los para trabalhar com Node.js. Neste caso,
o evento connect de um banco de dados, um open de um arquivo, não espere um alto salário e sim um amplo conhecimento preen-
um data de um streaming de dados e muitos outros. chendo o seu currículo.

Edição 02 • Front-end Magazine 17


Programação assíncrona com Node.js

• Ready for real-time: O Node.js ficou popular graças aos seus ou mesmo por simples chamadas jQuery Ajax. Com o Node.js,
frameworks de interação real-time entre cliente e servidor. O você pode simplesmente expor seus objetos JSON com uma API
SockJS, Socket.IO, Engine.IO são alguns exemplos disso. Eles são REST para o cliente a consumir. Além disso, você não precisa se
compatíveis com o recente protocolo WebSockets e permitem tra- preocupar com a conversão entre JSON e tudo aquilo que for ler
fegar dados através de uma única conexão bidirecional, tratando ou escrever em seu banco de dados (se estiver usando MongoDB).
todas as mensagens através de eventos JavaScript. Em suma, você pode evitar a necessidade de múltiplas conversões
• Big players: LinkedIn, Wallmart, Groupon, Microsoft e Paypal usando um formato de serialização de dados uniforme em todo
são algumas das empresas usando Node.js atualmente, no Brasil o cliente e servidor de banco de dados.
conheço algumas empresas por exemplo: Agendor, Sappos, Ne-
oassist e tem mais um monte de outras empresas e projetos (veja Entradas de Filas
na seção Links). Se você está recebendo uma grande quantidade de dados simul-
tâneos, o banco de dados pode se tornar um gargalo. O Node.js
Onde posso usar o Node.js? pode facilmente lidar com as próprias conexões simultâneas. Mas
porque o acesso a bancos de dados é uma operação bloqueante, nos
Chats depararemos certamente com problemas. A solução é reconhecer
Um chat é o mais típico exemplo de aplicação multi-usuário o comportamento do cliente antes de os dados serem realmente
em tempo real. Desde IRC até muitos protocolos proprietários gravados na base de dados.
e abertos sobre portas não-padrão, até mesmo a habilidade de Com essa abordagem, o sistema mantém a sua capacidade de res-
implementar tudo hoje no Noje.js com websockets rodando sobre posta sob uma carga pesada, o que é particularmente útil quando
a mesma porta padrão 80. o cliente não precisa de confirmação firme de uma gravação de
A aplicação de chat é realmente é um ótimo exemplo de ser dados bem-sucedida. Exemplos típicos incluem: o registro ou gra-
usada com Noje.js: é leve, tem alto tráfico de dados, porém exige vação de dados de rastreamento de usuário, com processamento
pouco processamento/computação e que executa dentre vários em lotes e não utilizados até mais tarde; bem como operações que
dispositivos. Além de tudo, é bem simples, ótimo para os de- não precisam ser refletidas instantaneamente (como a atualização
senvolvedores que estão iniciando o aprendizado na tecnologia, de um count ‘Likes’ no Facebook), onde a consistência eventual
cobrindo a maior parte dos paradigmas usados pela linguagem. (tantas vezes usada no mundo NoSQL) é aceitável.
Basicamente, uma aplicação desse tipo funciona dentro de um Os dados são colocados em fila por algum tipo de cache ou
domínio de website já pronto onde as pessoas podem ir e efetuar enfileiramento de mensagens de infraestrutura (por exemplo,
a troca de mensagens entre si conectados por uma estrutura de RabbitMQ, ZeroMQ) e digerido por um processo de banco de
programação e redes. No lado do servidor, temos uma aplicação dados separado em lotes e escrita, ou computação intensiva de
simples que implementa duas coisas: serviços de processamento de back-end, escrito em uma plata-
• Uma requisição GET que serve a página web contendo ambas forma de melhor desempenho para tais tarefas. Comportamento
mensagem e botão de enviar para inicializar uma nova entrada semelhante pode ser implementado com outras linguagens/
de mensagem; frameworks, mas não no mesmo hardware, com o mesmo alto
• Websockets que escutam por novas mensagens emitidas pelos rendimento mantido.
seus clientes.
Fluxo de Dados
No lado cliente nós temos uma página HTML com uma série de Em plataformas mais tradicionais da web, solicitações e respostas
handlers configurados, um para o botão de Envio, que seleciona HTTP são tratadas como eventos isolados; na verdade, eles são
a mensagem e a envia para o websocket, e outro que escuta por realmente streams. Esta observação pode ser utilizada no Node.
mensagens que estão chegando no cliente. Obviamente, este é um js para construir alguns recursos interessantes. Por exemplo,
modelo simples e básico, mas que baseia os demais em variância é possível processar arquivos enquanto eles ainda estão sendo
às suas complexidades. carregados, uma vez que os dados vêm no meio de um stream
e podemos processá-los de forma online. Isso poderia ser feito
API sobre um objeto DB para áudio em tempo real ou codificação de vídeo e proxy entre
Embora o Node.js realmente brilhe com aplicações em tempo as diferentes fontes de dados.
real, é natural ter que expor os dados a partir de um objeto de ban-
co de dados (MongoDB, por exemplo). Dados JSON armazenados Proxy
permitem que o Node.js funcione sem a diferença de impedância O Node.js é facilmente utilizado como um proxy do lado do servi-
e conversão de dados. Por exemplo, se você estiver usando Rails, dor, onde ele pode lidar com uma grande quantidade de conexões
você deve converter JSON para modelos binários e em seguida, simultâneas de uma maneira non-blocking. É especialmente útil
expô-los de volta como JSON sobre o HTTP quando os dados são para proxys de diferentes serviços com diferentes tempos de res-
consumidos por frameworks como o Backbone.js, Angular.js, etc., posta ou a coleta de dados a partir de vários pontos de origem.

18 Front-end Magazine • Edição 02


Considere como exemplo um aplicativo
que do lado do servidor se comunica com
recursos de terceiros, puxando dados de
diferentes fontes ou armazenando ativos
como imagens e vídeos para serviços em
nuvem de terceiros.
Embora existam servidores proxy dedi-
cados, utilizando Node.js, ao invés, pode
ser útil se a sua infraestrutura de proxy
é inexistente ou se você precisa de uma
solução para o desenvolvimento local.
Por isso, você pode construir um aplica-
tivo do lado do cliente com um servidor
de desenvolvimento Node.js para ativos
e solicitações de proxy/Stubbing API,
enquanto em produção você lidaria com
tais interações com um serviço dedicado
de proxy (nginx, HAProxy, etc.).
Figura 1. Configurando variável de ambiente no Windows 7
Painel de Monitoramento de Aplicações
Outro caso de uso comum, em que o Node com websockets se procedimentos serão diferentes para cada sistema, principalmente
encaixa perfeitamente é o rastreamento de visitantes do site e vi- para o Windows, mas não será nada grave.
sualização de suas interações em tempo real.
Você poderia reunir estatísticas em tempo real a partir de seu Instalação
usuário, ou mesmo movê-lo para o próximo nível através da in- O primeiro passo é acessar seu site oficial (ver seção Links).
trodução de interações específicas com seus visitantes, abrindo Em seguida, clique em Install para baixar automaticamente a
um canal de comunicação quando chegam a um ponto específico última versão compatível com seu sistema operacional (isto é
no seu filtro. se seu sistema é Windows ou MacOS).
Imagine como é possível melhorar um dado negócio, se for pos- Caso você use Linux recomendo que leia em detalhes a Wiki
sível saber o que os visitantes estavam fazendo em tempo real, do repositório Node.js (ver na seção Links), pois lá é explicado
se for possível visualizar suas interações. Com o tempo real, nos as principais instruções sobre como instalá-lo através de um
dois sentidos bases de Node.js, agora é possível. package manager de uma distribuição Linux.

Painel de Monitoramento de Sistemas


Agora, vamos visitar o lado da infraestrutura das coisas. Ima- Nota
gine, por exemplo, um provedor de SaaS que quer oferecer a seus Todos os códigos aplicados neste artigo funcionarão apenas em versões do Node.js 0.8.X ou superior,
usuários uma página de serviço de monitoramento (por exemplo, exceto o último exemplo do artigo que utiliza a implementação de Generators do ECMAScript 6 que
página de status do GitHub). Com o evento de circuito Node.js, somente vai funcionar em uma versão unstable do Node.js 0.11.X.
podemos criar um poderoso painel baseado na web que verifica
os estados dos serviços de forma assíncrona e envia dados para
os clientes que usam websockets. Agora instale-o e caso não ocorra problemas, basta abrir seu
Tanto interna quanto os status dos serviços públicos podem ser terminal ou prompt de comandos e digite o seguinte comando
relatados ao vivo e em tempo real, utilizando esta tecnologia. Indo para ver as respectivas versões do Node.js e NPM que foram
um pouco além com essa ideia e tentando imaginar um Centro instaladas:
de Operações de Rede (NOC) aplicações de monitoramento em
um operador de telecomunicações, nuvem/rede/provedor de node -v && npm -v
hospedagem, ou alguma instituição financeira, todos executados
na pilha web aberta apoiada pelo Node.js e websockets em vez de A última versão estável que está sendo utilizada neste artigo é
Java e/ou Java Applets, como foi visto por muito tempo. Node v0.10.31 e NPM 1.4.23.

Hands on Node.js Configurando o ambiente de desenvolvimento


Para configurar um ambiente Node.js, independente de qual Para configurar o ambiente de desenvolvimento basta adicio-
sistema operacional, as dicas serão as mesmas. Somente alguns nar a variável de ambiente NODE_ENV no sistema operacional.

Edição 02 • Front-end Magazine 19


Programação assíncrona com Node.js

Em sistemas Linux ou MacOS, basta acessar com um editor de • npm remove -g nome-do-modulo: desinstala um módulo global;
texto qualquer e em modo super user (sudo) o arquivo .bash_pro- • npm update nome-do-modulo: atualiza a versão do módulo;
file ou .bashrc e no final do arquivo adicione a seguinte linha • npm update -g nome-do-modulo: atualiza a versão do módulo
de comando: global;
• npm -v: exibe a versão atual do npm;
export NODE_ENV=’development’ • npm adduser nome-do-usuario: cria uma conta no npm através
do site do NPM (ver seção Links);
Clique com botão direito no ícone Meu Computador e selecione • npm whoami: exibe detalhes do seu perfil público npm (é ne-
a opção Propriedades e no lado esquerdo da janela clique no link cessário criar uma conta antes);
Configurações avançadas do sistema. Na janela seguinte, acesse • npm publish: publica um módulo no site do npm (é necessário
a aba Avançado e clique no botão Variáveis de Ambiente…. ter uma conta NPM antes).
Agora no campo Variáveis do sistema clique no botão Novo… e
no campo nome da variável digite NODE_ENV e no campo valor Entendendo o package.json
da variável digite development, tal como demonstrado na Figura 1. Todo projeto Node.js é chamado de módulo, mas o que é um
Após finalizar essa tarefa, reinicie seu computador para carregar módulo? No decorrer da leitura, perceba que vamos discutir muito
essa variável automaticamente no sistema operacional. sobre o termo módulo, biblioteca e framework, e, na prática, eles
possuem o mesmo significado. O termo módulo surgiu do conceito
Rodando o Node.js de que o JavaScript trabalha com uma arquitetura modular. E todo
Para testarmos o ambiente, executaremos o nosso primeiro pro- módulo é acompanhado de um arquivo descritor, conhecido pelo
grama de Hello World. Abra seu terminal ou prompt de comando e nome de package.json.
execute o comando node. Este comando vai acessar o modo REPL Este arquivo é essencial para um projeto Node.js. Um package.
(Read-Eval-Print-Loop) que permite executar códigos JavaScript json mal escrito pode causar bugs ou impedir o funcionamento
diretamente pela tela preta. Agora digite console.log(“Hello World”) correto do seu módulo, pois ele possui alguns atributos chaves
e tecle ENTER para executá-lo na hora (Figura 2). que são compreendidos pelo Node.js e NPM.
Na Listagem 1 temos um package.json que contém os principais
atributos para descrever um módulo.

Listagem 1. Formato de um package.json.

{
“name”: “meu-primero-node-app”,
“description”: “Meu primeiro app Node.js”,
“author”: “Caio <caio@email.com>”,
“version”: “1.2.3”,
“private”: true,
Figura 2. Hello World em Node.js via terminal “dependencies”: {
“modulo-1”: “1.0.0”,
“modulo-2”: “~1.0.0”,
“modulo-3”: “>=1.0.0”
Gerenciando dependências e módulos usando o NPM },
Assim como o RubyGems do Ruby ou o Maven do Java, o Node “devDependencies”: {
.js também possui seu próprio gerenciador de pacotes, ele se “modulo-4”: “*”
}
chama NPM. Ele se tornou tão popular pela comunidade, que foi }
a partir da versão 0.6.X que foi integrado no instalador do Node
.js, tornando-se o gerenciador padrão desta plataforma. Isto sim-
plificou a vida dos desenvolvedores na época, pois fez com que Com esses atributos, você já descreve o mínimo possível o que
diversos projetos se convergissem para esta plataforma até os dias será sua aplicação. O atributo name é o principal. Com ele, você
de hoje. Utilizar o NPM é muito fácil, então vejamos os comandos descreve o nome do projeto, nome pelo qual seu módulo será
principais para que você tenha noções de como usá-los: chamado via função require(‘meu-primeiro-node-app’). Em
• npm install nome-do-modulo: instala um módulo no projeto; description, descrevemos o que será este módulo. Ele deve ser
• npm install -g nome-do-modulo: instala um módulo global; escrito de forma curta e clara, fornecendo um resumo do mó-
• npm install nome-do-modulo --save: instala o módulo no pro- dulo. O author é um atributo para informar o nome e e-mail do
jeto, atualizando o package.json na lista de dependências; autor. Utilize o formato Nome <email> para que sites como npm
• npm list: lista todos os módulos do projeto; reconheça corretamente esses dados. Outro atributo principal
• npm list -g: lista todos os módulos globais; é o version, com o qual definimos a versão atual do módulo.
• npm remove nome-do-modulo: desinstala um módulo do projeto; É extremamente recomendado que tenha este atributo, se não

20 Front-end Magazine • Edição 02


será impossível instalar o módulo via comando npm. O atributo Esse conceito de variável global é existente na maioria das lin-
private é um booleano, e determina se o projeto terá código aberto guagens de programação, assim como sua utilização, portanto
ou privado para download no npm. é recomendado trabalhar com o mínimo possível de variáveis
Os módulos no Node.js trabalham com três níveis de versiona- globais para evitar futuros gargalos de memória na aplicação.
mento. Por exemplo, a versão 1.2.3 está dividida nos níveis: Major
(1), Minor (2) e Patch (3). Repare que no campo dependencies foram CommonJS
incluídos 4 módulos, sendo que cada um utilizou uma forma O Node.js utiliza nativamente o padrão CommonJS para organi-
diferente de definir a versão do projeto. O primeiro, o modulo-1, zação e carregamento de módulos. Na prática, diversas funções
somente será incluído sua versão fixa, a 1.0.0. Utilize este tipo ver- deste padrão serão utilizadas com frequência em um projeto
são para instalar dependências cuja atualizações possam quebrar Node.js. A função require(‘nome-do-modulo’) é um exemplo
o projeto pelo simples fato de que certas funcionalidades foram disso, ela carrega um módulo. E para criar um código modular,
removidas e ainda as utilizamos na aplicação. O segundo módulo carregável pela função require, utilizam-se as variáveis globais:
já possui uma certa flexibilidade de update. Ele utiliza o carac- exports ou module.exports. Veja nas listagens a seguir dois
tere “~” que faz atualizações a nível de patch (1.0.x). Geralmente exemplos de módulos para Node.js. Primeiro, crie o código hello
essas atualizações são seguras, trazendo apenas melhorias ou .js (Listagem 4) e depois crie o código human.js (Listagem 5).
correções de bugs. O modulo-3 atualiza versões que sejam maior
ou igual a 1.0.0 em todos os níveis de versão. Em muitos casos, Listagem 4. Criando um módulo com module.exports.
utilizar “>=” pode ser perigoso, porque a dependência pode ser
atualizada a nível major ou minor, contendo grandes modificações module.exports = function(msg) {
console.log(msg);
que podem quebrar um sistema em produção, comprometendo };
seu funcionamento e exigindo que você atualize todo código até
Listagem 5. Criando um módulo com exports.
voltar ao normal. O último, o modulo-4, utiliza o caractere “*”; este
sempre pegará a última versão do módulo em qualquer nível. Ele exports.hello = function(msg) {
também pode causar problemas nas atualizações e tem o mesmo console.log(msg);
};
comportamento do versionamento do modulo-3. Geralmente ele
é utilizado em devDependencies, que são dependências focadas
para testes ou de uso exclusivo para ambiente de desenvolvimento, A diferença entre o hello.js e o human.js está na maneira como
e as atualizações dos módulos não prejudicam o comportamento eles serão carregados. Em hello.js carregamos uma única função
do sistema que já está no ar. modular, e em human.js é carregado um objeto com funções mo-
dulares. Essa é a grande diferença entre eles. Para entender melhor
Escopos de variáveis locais e globais na prática, crie o código app.js para carregar esses módulos:
Assim como no browser, utilizamos o mesmo JavaScript no
Node.js. Ele também utiliza escopos locais e globais de variáveis. var hello = require(‘./hello’);
A única diferença é na forma como são implementados os escopos var human = require(‘./human’);
de variáveis globais. No browser, as variáveis globais são criadas hello(‘Olá pessoal!’);
da forma como pode ser vista na Listagem 2. human.hello(‘Olá galera!’);
Em qualquer browser, a palavra-chave window permite criar
variáveis globais que são acessadas em qualquer lugar. Já no Node Tenha certeza de que esses módulos hello.js, human.js e app.js
.js, utilizamos a palavra-chave global para aplicar essa mesma estão na mesma pasta, e em seguida, rode o comando:
técnica (Listagem 3).
node app.js

Listagem 2. Variáveis globais no client-side.


E então, o que aconteceu? O resultado foi praticamente o mes-
window.hoje = new Date(); mo: o app.js carregou os módulos hello.js e human.js via função
alert(window.hoje);
require(), em seguida foi executada a função hello(“Olá pessoal!”)
Listagem 3. Variáveis globais no server-side do Node.js. que imprimiu a mensagem “Olá pessoal!” e, por último, o objeto
human executou sua função human.hello(‘Olá galera!’).
global.hoje = new Date();
console.log(global.hoje); Um detalhe final é que também é possível criar um objeto com
função modular usando module.exports, apenas faça com que o
módulo retorne um objeto com funções públicas, semelhante ao
Ao utilizar global mantemos uma variável global, acessível em código da Listagem 6.
qualquer parte do projeto sem a necessidade de chamá-la via E assim você terá um módulo com mesmo comportamento do
require ou passá-la por parâmetro em uma função. human.hello(“olá”).

Edição 02 • Front-end Magazine 21


Programação assíncrona com Node.js

Listagem 6. Emulando o comportamento das funções exports usando module. módulos. O text_sync.js, por ser um código síncrono, invocou
exports. chamadas de I/O bloqueantes e gerou o gráfico da Figura 3.
module.exports = function() {
Repare no tempo de execução, o text_sync.js hipoteticamente
return { demorou 1000 milissegundos, isto é, 200 milissegundos para
hello: function(msg) { cada escrita de arquivo. Já em text_async.js foram criados os
console.log(msg);
} arquivos de forma totalmente assíncrona, ou seja, as chamadas
}; de I/O eram não-bloqueantes, e isso permitiu escrever arquivos
}; em paralelo, como na Figura 4.

Programando de forma assíncrona


Agora vamos para a última parte do nosso artigo. Agora que
já temos uma base sobre o que é e como usar o Node.js, vamos
focar em aprender boas práticas sobre funções assíncronas.
Afinal este é o paradigma principal desta plataforma, e é muito
importante dominar esses conceitos para se tirar melhor proveito
desta tecnologia, assim como entender como funciona funções
assíncronas. O código a seguir exemplifica as diferenças entre
uma função síncrona e assíncrona em relação à linha do tempo
Figura 3. Timeline de execução síncrona
na qual elas são executadas. Basicamente, criaremos um loop de
cinco iterações, sendo que a cada iteração será criado um arquivo
texto com o mesmo conteúdo “Hello Node.js!”. Primeiro vamos
começar com o código síncrono. Crie o arquivo text_sync.js com
o código da Listagem 7.
Agora vamos criar o arquivo text_async.js, com seu respec-
tivo código, diferente apenas na forma de chamar a função
fs.writeFileSync, que será a versão assíncrona fs.writeFile, pelo
qual seu retorno de sucesso acontece através da execução de uma
função de callback existente no terceiro argumento da função
(Listagem 8).
Figura 4. Timeline de execução assíncrona

Listagem 7. Escrevendo arquivo de texto de forma síncrona.


Isto fez com que o tempo de execução levasse hipoteticamente
var fs = require(‘fs’); 200 milissegundos, afinal foi invocada cinco vezes, em paralelo,
for(var i = 1; i <= 5; i++) { a função fs.writeFile, e isso maximizou o uso de processamento
var file = “sync-txt” + i + “.txt”;
fs.writeFileSync(file, “Hello Node.js!”); e I/O e minimizou o tempo de execução. Só para finalizar esse
console.log(“Criando arquivo: “ + file); gráfico é apenas hipotético, e foi usado para exemplificar como
} funciona o assincronismo do Node.js, nem sempre um conjunto
Listagem 8. Escrevendo arquivo de texto de forma assíncrona. de funções assíncronas vão executar em paralelo de forma tão
perfeita como foi apresentado nesses gráficos.
var fs = require(‘fs’);
for(var i = 1; i <= 5; i++) {
var file = “async-txt” + i + “.txt”; Threads vs Assincronismo
fs.writeFile(file, “Hello Node.js!”, function(err, out) { Por mais que as funções assíncronas possam executar em pa-
console.log(“Criando arquivo: “ + file);
});
ralelo várias tarefas, elas jamais serão consideradas uma Thread
} (por exemplo as Threads do Java). A diferença é que Threads são
manipuláveis pelo desenvolvedor, ou seja, você pode pausar a
execução de uma Thread ou fazê-la esperar o término de uma
Execute os comandos node text_sync.js e depois node text_async outra Thread para ser executada. Chamadas assíncronas apenas
.js. Se forem gerados 10 arquivos no mesmo diretório do código- invocam suas funções em e você não controla elas, apenas trabalha
fonte, então deu tudo certo. Mas a execução de ambos foi tão rápida com seus retornos através de uma função callback.
que não foi possível visualizar as diferenças entre o text_async.js Pode parecer vantajoso ter o controle sobre a execução de
e o text_sync.js. Para entender melhor as diferenças, veja os grá- Threads a favor de um sistema que executa tarefas em paralelo,
ficos hipotéticos a seguir que ocorrem quando executamos esses mas pouco conhecimento sobre eles pode transformar seu sis-

22 Front-end Magazine • Edição 02


tema em um caos de travamentos de dead-locks, afinal elas são conteúdo, no término de cada leitura será apresentado o tempo
executadas de forma bloqueante. Este é o grande diferencial das de bloqueio que cada módulo obteve, como observado através
chamadas assíncronas, elas executam em paralelo suas funções da Listagem 11.
sem travar processamento das outras e, principalmente, sem
bloquear a aplicação. Listagem 11. Código de execução do benchmark síncrono vs assíncrono.
É fundamental que o seu código Node.js invoque o mínimo
var http = require(‘http’);
possível de funções bloqueantes. Toda função síncrona impedirá, var fs = require(‘fs’);
naquele instante, que o Node.js continue executando os demais var leituraAsync = require(‘./leitura_async’);
códigos até que aquela função seja finalizada. Por exemplo, se essa var leituraSync = require(‘./leitura_sync’);
var arquivo = “./node.exe”;
função fizer um I/O em disco, ele vai bloquear o sistema inteiro, var stream = fs.createWriteStream(arquivo);
deixando o processador ocioso enquanto ele utiliza outros recur- var download = “http://nodejs.org/dist/latest/x64/node.exe”;
sos do servidor, como por exemplo leitura em disco, utilização http.get(download, function(res) {
console.log(“Fazendo download do Node.js”);
da rede etc. Sempre que puder, utilize funções assíncronas para res.on(‘end’, function(){
aproveitar essa característica principal do Node.js. console.log(“Download finalizado!”);
console.log(“Executando benchmark sync vs async...”);
leituraAsync(arquivo);
Assincronismo versus Sincronismo leituraSync(arquivo);
Caso você ainda não esteja convencido sobre as vantagens do });
});
processamento assíncrono vou lhe mostrar como e quando utili-
zar bibliotecas assíncronas não-bloqueantes através de um teste
prático. Rode o comando node processamento.js para executar o bench-
Para exemplificar melhor, os códigos adiante representam um mark. E agora, ficou clara a diferença entre o modelo bloqueante
benchmark comparando o tempo de bloqueio de execução assín- e o não-bloqueante? Parece que o módulo leituraAsync executou
crona vs síncrona. Para isso, crie três arquivos: processamento. muito rápido, mas não quer dizer que o arquivo foi lido. Ele recebe
js, leitura_async.js e leitura_sync.js. Criaremos isoladamente o um último parâmetro, que é um callback indicando quando o
módulo leitura_async.js que será responsável por fazer leitura arquivo foi lido, que não passamos na invocação que fizemos.
assíncrona de arquivo grande, tal como na Listagem 9. Ao usar o fs.readFileSync(), bastaria fazer var conteudo =
Em seguida, crie o módulo leitura_sync.js, que realizará leitura fs.readFileSync(). Mas qual é o problema dessa abordagem? Ela
síncrona no mesmo arquivo (Listagem 10). bloqueia todo o processamento da aplicação! Somente quando o
bloqueio terminar as demais linhas de código serão executadas,
Listagem 9. Código de benchmark de tempo de bloqueio em leitura assíncrona. em contra partida o fs.readFile() continua executando qualquer
código que não estiver dentro de seu callback, então com isso você
var fs = require(‘fs’); pode, por exemplo, programar sua aplicação para fazer outras
var leituraAsync = function(arquivo){
console.log(“Fazendo leitura assíncrona”); tarefas em paralelo.
var inicio = new Date().getTime(); A seguir, temos o resultado do benchmark realizado em na
fs.readFile(arquivo);
máquina que possui as seguintes configurações:
var fim = new Date().getTime();
console.log(“Bloqueio assíncrono: “+(fim - inicio)+ “ms”); • MacBook Air 2011;
}; • Processador: Core i5 1.6GHz;
module.exports = leituraAsync;
• Memória: 4GB DDR 3;
Listagem 10. Código de benchmark de tempo de bloqueio em leitura síncrona. • Disco: 128GB SSD.

var fs = require(‘fs’);
var leituraSync = function(arquivo){ Veja a pequena, porém significante, diferença de tempo entre as
console.log(“Fazendo leitura síncrona”); duas funções de leitura realizada na máquina (Figura 5).
var inicio = new Date().getTime();
fs.readFileSync(arquivo);
var fim = new Date().getTime();
console.log(“Bloqueio síncrono: “+(fim - inicio)+ “ms”);
};
module.exports = leituraSync;

Para finalizar, vamos carregar esses módulos dentro do código


processamento.js. Basicamente este módulo principal vai fazer
download da última versão do instalador Node.js que tem em
média 7 MB de tamanho. Quando o download terminar ele vai
enviar o arquivo para os módulos realizarem uma leitura de Figura 5. Resultado do benchmark I/O Async vs I/O Sync

Edição 02 • Front-end Magazine 23


Programação assíncrona com Node.js

Evitando Callbacks Hell seu código. Em resumo Generators é um recurso que permite es-
De fato, vimos o quanto é vantajoso e performático trabalhar de crever funções assíncronas sem callbacks, utilizando uma sintaxe
forma assíncrona, porém, em certos momentos, inevitavelmente de código síncrono, retornando valores da função em um array que
implementaremos diversas funções assíncronas, que serão enca- representa os possíveis parâmetros de uma função callback.
deadas uma na outra através de suas funções callback. No código
da Listagem 12 vemos um exemplo desse caso.
Listagem 13. Minimizando callback hell declarando funções em variáveis.

Listagem 12. Exemplo de Callback Hell. var fs = require(‘fs’);


var lerDiretorio = function() {
var fs = require(‘fs’); fs.readdir(__dirname, function(erro, diretorio) {
fs.readdir(__dirname, function(erro, contents) { if (erro) return erro;
if (erro) { throw erro; } diretorio.forEach(function(arquivo) {
contents.forEach(function(content) { ler(arquivo);
var path = ‘./’ + content; });
fs.stat(path, function(erro, stat) { });
if (erro) { throw erro; } };
if (stat.isFile()) { var ler = function(arquivo) {
console.log(‘%s %d bytes’, content, stat.size); var path = ‘./’ + arquivo;
} fs.stat(path, function(erro, stat) {
}); if (erro) return erro;
}); if (stat.isFile()) {
}); console.log(‘%s %d bytes’, arquivo, stat.size);
}
});
};
Reparem na quantidade de callbacks encadeados que existem lerDiretorio();
em nosso código. Detalhe: ele apenas faz uma simples leitura dos
arquivos de seu diretório e imprime na tela seu nome e tamanho
em bytes. Uma pequena tarefa como essa deveria ter menos enca- Como esse recurso ainda não é oficial, somente alguns browsers
deamentos, concorda? Agora, imagine como seria a organização (últimas versões do Chrome e Firefox) o utilizam no client-side.
disso para realizar tarefas mais complexas? Praticamente o seu Já no server-side temos que habilitar no Node.js, porém somente
código seria um caos e totalmente difícil de fazer manutenções. existe para as versões instáveis: 0.11.X e possivelmente será ofi-
Por ser assíncrono, você perde o controle do que está executando cializada na próxima versão estável: 0.12.x.
em troca de ganhos com performance, porém, um detalhe impor-
tante sobre assincronismo é que, na maioria dos casos, os callbacks Observação
bem elaborados possuem como parâmetro uma variável de erro.
Para utilizar uma versão 0.11.X recomendo que faça download e instalação das versões Nightlies
Verifique nas documentações sobre sua existência e sempre faça o
do Node.js (ver na seção Links). Lembrando que não recomendado utilizar uma versão instável em
tratamento deles na execução do seu callback: if (erro) { throw erro;
uma aplicação em produção.
}. Isso vai impedir a continuação da execução aleatória quando
for identificado um erro.
Uma boa prática de código JavaScript é criar funções que ex- Com a versão 0.11.X instalada em sua máquina, basta executar
pressem seu objetivo e de forma isoladas, salvando em variável e suas aplicações utilizando a flag —harmony, por exemplo:
passando-as como callback. Ao invés de criar funções anônimas,
por exemplo, crie um arquivo chamado callback_heaven.js com o node --harmony app.js
código da Listagem 13.
Veja o quanto melhorou a legibilidade do seu código. Dessa Com harmony habilitado, podemos usar alguns recursos do
forma deixamos mais semântico e legível o nome das funções e ES6, incluindo o Generators. Porém será necessário uma instalar
diminuímos o número de encadeamentos das funções de call- uma biblioteca adicional que permite trabalhar com Generators
back. A boa prática é ter o bom senso de manter no máximo até e também faz algumas magias extras. Para isso instale o módulo
dois encadeamentos de callbacks. Ao passar disso, significa que suspend. Antes de criarmos os códigos de Callback e Generators,
está na hora de criar uma função externa para ser passada como instale o módulo suspend utilizando o seguinte código:
parâmetro nos callbacks, em vez de continuar criando um callback
hell em seu código. npm install suspend --save

Evitando Callbacks Hell usando Generators Agora vamos a implementação. A seguir temos dois códigos que
Muitos recursos interessantes estão surgindo para a nova especifi- fazem a mesma tarefa: ambos criam um arquivo de texto, escreve
cação JavaScript conhecida por ECMAScript6 ou ES6, o Generators nele um timestamp e, no fim, excluir o próprio arquivo gerado.
é um deles e seu objetivo principal é minimizar callback hell em O código da Listagem 14 utiliza vários call-backs.

24 Front-end Magazine • Edição 02


Na Listagem 15 temos a segunda parte do código, que é uma Agora, imagine esta mesma ação em larga escala, lendo múltiplos
versão otimizada que implementa Generators para lidar com os arquivos de 1 GB ao mesmo tempo ou realizando múltiplos I/Os
call-backs. em seu servidor para milhares de usuários, tudo isso sem bloquear
a aplicação. Esse é um dos pontos fortes do Node.js!
Listagem 14. Outro exemplo de callback hell.

var fs = require(“fs”);
var time = new Date().getTime();
Autor
fs.writeFile(“log.txt”, time, function(err) { Caio Ribeiro Pereira
console.log(“Iniciando log”);
fs.readFile(“log.txt”, function(err, text) {
caio.ribeiro.pereira@gmail.com
console.log(“Timestamp: “ + text); É um Web Developer, com experiência nessa sopa de letrinhas:
fs.unlink(“log.txt”, function() { Node.js, Meteor, JavaScript, CSS, Ruby, Java, MongoDB, Redis,
console.log(“Log finalizado”); LevelDB, Agile, XP e TDD. Bacharel em Sistemas de Informação, mantém
});
ativamente o blog Underground WebDev abordando assuntos sobre Node
});
}); .js, JavaScript, apaixonado por programação, tecnologias e seriados. Moderador do Meteor
Brasil e participante das comunidades NodeBR e DevInSantos. Desde 2011 palestra nos
Listagem 15. Implementando Generators para minimizar callback hell. eventos DevInSantos e Exatec, abordando temas atuais sobre Node.js e JavaScript. Autor
dos livros da Casa do Código: Aplicações web real-time com Node.js e Meteor - Criando
var fs = require(‘fs’);
var suspend = require(‘suspend’);
aplicações web real-time com JavaScript.
var resume = suspend.resume;
var time = new Date().getTime();
suspend(function* (){
yield fs.writeFile(“log.txt”, time, resume()); Links:
console.log(“Iniciando log”);
var text = yield fs.readFile(“log.txt”, resume()); Blog Underground WebDev
console.log(“Timestamp” + text); www.udgwebdev.com/
yield fs.unlink(“log.txt”, resume());
console.log(“Log finalizado”); Ruby EventMachine
})();
www.rubyeventmachine.com/

Python Twisted
Simplesmente o encadeamento de callbacks diminuiu com Gene- www.twistedmatrix.com/
rators, e isso deixou seu código mais limpo e menos complexo.
Google Groups NodeBR
De fato o Node.js é uma excelente opção para desenvolvedores www.groups.google.com/forum/#!forum/nodebr/
front-end conhecerem um pouco sobre back-end sem precisar
aprender uma nova linguagem, afinal esta plataforma o mesmo Ja- Site oficial do Node.js
vaScript client-side, apenas com alguns detalhes diferentes. Outro www.nodejs.org/
detalhe importante é sobre as vantagens das funções assíncronas Wiki de instalação do Node.js
e seu I/O não-bloqueante. Afinal como vimos em um benchmark, www.github.com/joyent/node/wiki/Installing-Node.js-via-package-manager/
testamos uma ação de I/O simples que fazia uma leitura de um
Site oficial do NPM
único arquivo de mais ou menos 7 MB e o tempo de bloqueio foi
www.npmjs.org/
muito menor do que uma leitura bloqueante.

Edição 02 • Front-end Magazine 25


Testes unitários em
JavaScript: Introdução -
Parte 1
Conheça o que há de mais recente e em evidência
no mercado de testes unitários para o cliente side

Este artigo faz parte de um curso Fique por dentro


Nenhuma categoria do ciclo de vida de software está em tanta
evidência quanto os testes unitários. Ao mesmo passo, o advento das

N
o advento das tecnologias front-end e da utili- tecnologias front-end, aliado aos processos e boas práticas que cada
zação de novos padrões de desenvolvimento, vez mais se fazem necessários de serem aplicados a esse meio, trazem
como a HTML5, novas fórmulas e conceitos à tona a real necessidade de unir ambos universos: testes de unidade
foram criados de forma a suprir a cada vez maior ne- ao desenvolvimento client side.
cessidade de atender a todos os diversos cenários de Este artigo explicita isso trazendo a primeira de duas partes sobre
software. o desenvolvimento de testes unitários usando JavaScript. Veremos
O uso de testes unitários para verificar se um módulo todos os conceitos, práticas e metodologias que norteiam o que há
ou unidade do código está funcionando corretamente de mais recente no assunto, assim como modelos básicos de como
como esperado já não constitui nenhuma novidade. eles se aplicam ao uso do JavaScript e seus frameworks.
Afinal, tal conceito foi outrora introduzido na comu-
nidade de desenvolvedores por Kent Beck, através de
linguagens mais antigas como Smalltalk, C, C++ e até mais famosos dos testes, desde os conceitos, teorias e boas práticas,
mesmo no Java. Porém, se analisarmos bem o termo é até a escolha das ferramentas adequadas para tal.
sempre extremamente associado às linguagens que se
constituem “linguagens server side”, isto é, executam Testes unitários
apenas do lado do servidor, muitas com processos bem Antes de entender quais divisões ou aplicações de testes diversas
definidos de compilação, interpretação, plataforma existem no universo de programação, é importante antes entender
integrada ou multiplataforma, etc. Até mesmo uma o que é, de fato, um teste unitário. O próprio nome já consegue
rápida busca na web pelo termo irá remeter em inúme- nos dizer muito acerca desse procedimento: um teste ou mais
ras bibliografias, blogs e sites sobre o assunto com foco testes que verificam unidades de composição de, no nosso caso,
voltado para esse tipo de linguagem. sistemas diversificados.
É interessante notar que até mesmo o conceito foi Se procurarmos mais formalmente, veremos algumas definições
desenvolvido e evoluído sobre esse tipo de linguagem. mais elaboradas: “Em programação de computadores, teste unitá-
Diante disso, este artigo visa construir uma ideia adap- rio ou teste de unidade constitui um método de teste de software
tada dos testes unitários para o universo front-end, pelo qual unidades individuais de código fonte, configuradas com
especificamente focado no uso e construção dos exem- um ou mais módulos de programas de computador juntos com
plos em cima da linguagem de script mais famosa do dados de controle associados são testados para determinar se eles
mercado: JavaScript. Logo, aqui abordaremos os tópicos estão aptos para o uso final.”

26 Front-end Magazine • Edição 02


Se pensarmos programaticamente uma unidade de código, e • Uma vez escrito, ele deve ser mantido para usos futuros;
consequentemente de software, deve constituir o menor pedaço • Qualquer um deve estar apto a executá-lo;
testável de uma aplicação. Em linguagens orientadas a objetos • Ele deve executar através do clique de um botão;
isso pode representar um método, ou até mesmo um bloco menor • Ele deve executar rapidamente.
de código fonte. Porém, quando partimos para o paralelo das
linguagens procedurais essa mesma unidade pode significar o Com um teste unitário, o sistema sobre o teste (SUT) deve ser
módulo inteiro programado, mesmo sendo comuns as divisões pequeno e apenas relevante para os desenvolvedores que traba-
por módulos menores ou funções e procedures individuais. lham proximamente ao código. Um teste unitário deve conside-
Em resumo, os testes unitários nos permitem adentrar métodos rar operações do tipo: código lógico, código que contém muitos
e classes para verificar a consistência da implementação dos branches, cálculos or algo que de alguma forma requeira algum
mesmos. E isso significa que uma bateria de testes bem elaborada tipo de decisão. Simples métodos getters e setters são exemplos
traz consigo uma carga de segurança alta em relação ao código de código não lógico.
implementado, uma vez que temos agora uma camada que segu- Quando um software é desenvolvido sob a perspectiva do teste
ramente avalia todas as unidades de código quando da refatoração unitário, a combinação de escrever um teste unitário para espe-
ou alteração dos mesmos. Em outras palavras, é possível introdu- cificar a interface mais o refactoring das atividades depois que o
zir novas partes ao código existente (um método, por exemplo) e teste passa constituem o design formal do teste. Cada teste unitário
poder verificar sua consistência de igual forma. pode ser visto como um elemento de design especificando classes,
Alguns desenvolvedores, no entanto, consideram que a prática métodos e comportamentos observáveis. O teste exemplificado na
de escrever “código para testar código” constitui um desperdí- Listagem 1 ilustra bem essa ideia.
cio de tempo, tempo este que poderia ser usada para focar nas Na mesma listagem é possível observar um conjunto de casos de
próximas iterações de desenvolvimento, bugs, ou quaisquer ati- teste que especificam um número de elementos da implementação.
vidades associadas. Porém, quando se trata do desenvolvimento A interface Soma é responsável por manter o contrato de assina-
de aplicações, com várias pessoas trabalhando na mesma equipe turas de acordo com a sua classe de implementação, SomaImpl.
(muitas delas alterando os mesmos pontos de código), com várias A implementação verifica (assert) o comportamento de diferentes
iterações, versões do código e dependendo da complexidade do chamadas (situações, casos) ao método add().
sistema, os testes unitários vêm para, na verdade, salvar tempo. Neste caso, os testes unitários, tendo sido escritos antes, atuam
Basta considerar o mapeamento de erros que te deixaria rápida e como um documento de design especificando a forma e compor-
seguramente atualizar o código fonte, por exemplo. tamento de uma determinada solução, mas não detalhes de im-
A ideia de testar partes do código como um todo não é recente, plementação, que serão deixados para o desenvolvedor. Seguindo
data de meados de 1970, quando Kent Beck, um dos responsáveis o paradigma “Faça a mais simples coisa que possa possivelmente
também pela metodologia de desenvolvimento ágil XP (Extreme funcionar”, a solução mais fácil que irá fazer com que o teste passe
Programming), idealizou o conceito baseado na necessidade está na classe SomaImpl e interface Soma.
de mais produtividade quando da aplicação de mudanças ao Ao contrário de outros métodos de design, usar testes unitários
software durante o seu ciclo de vida. A consolidação, porém, só como uma especificação de design tem uma vantagem significa-
veio quando da criação dos frameworks xUnit, que permitiam a tiva: o documento de design pode ser usado para verificar se a
verificação de partes separadas do código-fonte com os mesmos implementação “adere” ao design. Com esse método de design os
fins descritos até então. testes nunca passarão se os desenvolvedores não implementarem
Como o termo até então remetia apenas à linguagem Smalltalk, a solução de acordo com o design.
e com a popularização crescente do Java, tornou-se necessário
então a criação de um framework para a linguagem, daí nasceu Tipos de teste
o famoso JUnit. Apesar de ser uma linguagem server side (no É extremamente importante saber a diferença entre os tipos
conceito de aplicações cliente-servidor), o Java e o JUnit tiveram de teste existentes, bem como suas nomenclaturas e conceitos.
papel de extrema importância para a popularização e aceitação Existem três divisões principais de testes: o teste de unidade (que
dos testes unitários por parte dos desenvolvedores de uma forma tratamos aqui), de integração e de sistema. Vejamos as diferenças
geral. A partir dessa linguagem, foi que tivemos uma comunidade do teste de unidade para com as outras:
ativa e aberta à discussão do assunto, além de contribuir para a • O teste de integração, como o próprio nome já diz, é o teste
evolução do conceito e respectivas implementações. responsável por averiguar a integração entre duas partes do seu
sistema. Um dos exemplos mais clássicos desse tipo de teste é re-
Design do teste presentado pelo padrão de projetos DAO, que faz acesso à base de
Existem uma série de propriedades a serem consideradas quando dados para persistir as informações manipuladas pela linguagem
da criação e utilização de testes unitários: de programação. Ao desenvolver testes para uma classe desse
• Ele deve ser automatizado e permitir repetição; tipo você automaticamente estará criando um meio de verificar
• Ele deve ser fácil de implementar; se a “integração” entre ambos, código e banco de dados, existe

Edição 02 • Front-end Magazine 27


Testes unitários em JavaScript: Introdução - Parte 1

e está conforme. Existem vários outros tipos de integrações que dada a necessidade do outro ambiente para tal teste. Além disso,
podem ser verificadas via testes de integração, tais como código vale frisar a importância do teste bem feito, o que quase sempre
que se comunica com web services, que efetuam operações de significará ter testes para ambas as situações onde o teste funciona
escrita e leitura sobre arquivos, que verificam a comunicação e quebra.
assíncrona da implementação de filas e JMS, ou até mesmo que
verificam o funcionamento de mensagens enviadas via sockets, Tipos de processos
por protocolos HTTP, etc. Além de analisar os tipos de testes que existem, é importante
• O teste de sistema é uma expressão usada para designar se o também saber a diferença entre estes e os diferentes tipos de
funcionamento do sistema como um todo está procedendo. O foco, processos de teste que existem e que envolvem todo esse ciclo.
portanto, deixar de ser a unidade (teste unitário) assim como a Essas famosas “práticas de desenvolvimento” se dividem em
integração (teste de integração) e passa agora a focar na junção três nomes tão famosos quanto: TDD - Test-Driven Development,
de todas as pequenas partes do sistema constituindo o conjunto BDD - Behavior-driven Design e DDD - Domain-driven Design
completo de tarefas a serem executadas pelo sistema. Também (Figura 1).
chamado de “teste de caixa preta”, esse tipo de teste lida com a
averiguação de tudo, desde o banco de dados, métodos e classes
até as integrações. Para algumas vertentes, os testes de aceitação,
que ficaram famosos com o advento do desenvolvimento ágil e
são caracterizados pela aceitação ou não do time ágil, são no final
testes de sistema.

Diante dessa situação, muitos desenvolvedores se perguntam


qual tipo de teste escolher e/ou como associar cada nível de
teste a uma situação em específico no ciclo de desenvolvimento
do mundo real. Na verdade, não existe bala de prata, é preciso
ter o discernimento de associar cada situação a um tipo de teste
específico. Por exemplo, as classes responsáveis por lidar com o
negócio da aplicação geralmente podem ser testadas em unidade,
de uma maneira isolada, enquanto classes que se comunicam
com web services necessitam de um teste de integração aplicado, Figura 1. Três tipos de processos de desenvolvimento usando testes

Listagem 1. Exemplo de teste unitário em Java

public class AdicaoTeste { public void testeSomaNumerosNegativos() {


Soma soma = new SomaImpl();
// pode somar números positivos 1 e 1? assert(soma.add(-1, -2) == -3);
public void testeSomaNumeroPositivoUmEUm() { }
Soma soma = new SomaImpl();
assert(soma.add(1, 1) == 2); // pode somar um número positivo e um negativo?
} public void testeSomaPositivoENegativo() {
Soma soma = new SomaImpl();
// pode somar os números positivos 1 e 2? assert(soma.add(-1, 1) == 0);
public void testeSomaNumeroPositivoUmEDois() { }
Soma soma = new SomaImpl();
assert(soma.add(1, 2) == 3); // E quanto aos números grandes?
} public void testeSomaNumerosGrandes() {
Soma soma = new SomaImpl();
// pode somar os números positivos 2 e 2? assert(soma.add(1234, 988) == 2222);
public void testeSomaNumeroPositivoDoisEDois() { }
Soma soma = new SomaImpl(); }
assert(soma.add(2, 2) == 4);
} interface Soma {
int add(int a, int b);
// O zero é neutro? }
public void testeSomaZeroNeutro() { class SomaImpl implements Soma {
Soma soma = new SomaImpl(); int add(int a, int b) {
assert(soma.add(0, 0) == 0); return a + b;
} }
}
// pode somar os números negativos -1 e -2?

28 Front-end Magazine • Edição 02


TDD
O TDD, Test-Driven Development (ou Desenvolvimento Orien-
tado a Testes) é uma metodologia famosa que cresceu junto com
o desenvolvimento ágil e que foca no lema “testar primeiro,
desenvolver depois”. Em outras palavras, é uma técnica que
visa iterações curtas e que propõe que um dado desenvolvedor
implemente primeiramente o caso de teste específico para uma
situação de construção de funcionalidade, correção de bug, etc.,
e em seguida, e somente em seguida, crie o código fonte que
atenderá e será validado pelo caso de teste feito anteriormente.
Ele ganhou mais atenção nos anos posteriores como diferentes
metodologias junto ao processo de software que vinha surgindo.
Dissecando o nome, desenvolvimento sugere um processo de
pleno direito com a análise, projeto lógico e físico, implementa-
ção, teste, análise, integração e implantação, e orientado a testes
implica o quão concreto os testes automatizados devem conduzir
o processo de desenvolvimento. O TDD também é comumente
Figura 2. Fluxo de execução do TDD
chamado de programação test-first.
Quando se houve falar sobre essa terminologia, principalmente
associada a uma explicação do seu conceito, a ideia é aparen- Os testes com certeza falharão porque a função ainda não foi
temente simples. Apenas dando uma breve olhada na própria escrita, mas é justamente essa a intenção: verificar como o compor-
palavra é possível ver que TDD remete a ter testes que dirigem o tamento do código deveria funcionar, mesmo não tendo um código
desenvolvimento do software. ainda para testes. Agora que já entendemos a abordagem nua e
Se adentramos um pouco além na definição desse conceito, nos crua, criemos o código da função que irá satisfazer os testes. Ele
deparamos com cinco diferentes estágios: deverá se parecer com o código representado pela Listagem 3.
1. Antes de qualquer coisa, o desenvolvedor escreve alguns
testes;
Listagem 2. Exemplo de TDD com JavaScript Mocha
2. O desenvolvedor então executa alguns destes testes e (obvia-
mente) eles irão falhar porque nenhuma destas features estão de var assert = require(‘assert’), fatorial = require(‘../index’);
fato implementadas; suite(‘Teste’, function (){
setup(function (){
3. Em seguida, o desenvolvedor na verdade implementa todos // Cria quaisquer objetos que possam ser necessários
os testes feitos antes, agora em código fonte da linguagem esco- });
lhida; suite(‘#fatorial()’, function (){
test(‘igual a 1 para configurações de tamanho zero’, function (){
4. Se o desenvolvedor escreve o seu código bem, então no próximo assert.equal(1, fatorial(0));
estágio ele irá ver seus testes serem executados com sucesso; });
test(‘igual a 1 para configurações de tamanho um’, function (){
5. O desenvolvedor pode agora refatorar seu código, adicionar
assert.equal(1, fatorial(1));
comentários, limpar o projeto de uma forma geral, como ele deseja });
porque o desenvolvedor sabe que se o código novo quebrar em test(‘igual a 2 para configurações de tamanho dois’, function (){
assert.equal(2, fatorial(2));
algum local, então os testes irão alertá-lo sobre a falha.
});
test(‘igual a 6 para configurações de tamanho três’, function (){
O ciclo pode somente continuar se o desenvolvedor tem mais assert.equal(6, fatorial(3));
});
features a adicionar. Veja na Figura 2 a representação desse });
fluxo. });
Vejamos um exemplo então de como um desenvolvedor deveria
Listagem 3. Resultado de comando de execução do Java version
fazer isso. Digamos que um desenvolvedor quer escrever uma
função que faz algo bem simples, como calcular um fatorial (ob- module.exports = function (val) {
if (val < 0) {
viamente um exemplo bem simples, mas isso será o suficiente para
return NaN;
descrever como o comportamento TDD deva ser). A abordagem }
normal para TDD indica usar a função e então o assert para que if (val === 0) {
return 1;
o resultado satisfaça um determinado valor.
}
Os testes deverão ser parecidos com o código demonstrado na
Listagem 2, totalmente desenvolvido sobre o framework Java- return val * fatorial(val - 1);
};
Script Mocha.

Edição 02 • Front-end Magazine 29


Testes unitários em JavaScript: Introdução - Parte 1

Agora se executarmos os testes, poderemos ver que todos eles • Análises do tipo up-front, design e planejamento têm um retorno
passarão com sucesso. Isso é como o TDD funciona. cada vez menor.
Ao utilizar esse tipo de processo, alguns benefícios se tornam
claros logo já, como o baixo acoplamento com uma série de testes O primeiro princípio base está solidificado sobre a user story,
que comprovam o seu comportamento. Um dos resultados mais escrita conforme mostramos acima, de uma maneira não-técnica.
visíveis do TDD é que os testes desenvolvidos sobre o mesmo Essa noção de linguagem natural segue muitos frameworks BDD,
fornecem uma espécie de documentação informal do sistema, mesmo em um nível de código. O segundo princípio base de adi-
conforme falamos anteriormente, ditando não só o que o sistema cionar valor de negócio pode ser visto na história como a parte
pode fazer mas também o que não deve fazer (e é aí onde entram “Que então [beneficia]”.
os testes falhos). Além disso, pelo simples fato de tudo isso estar O terceiro princípio tem o mesmo significado do processo TDD.
integrado ao software, podemos dizer que o produto teste nunca Um design upfront é feito da forma mais pequena o possível, mesmo
ficará ultrapassado, o que difere das atividades de escrita de que o design esteja indo por além do teste e refactoring.
documentação e/ou comentar código. Juntos os princípios ajudam os desenvolvedores a mitigar os riscos
Alguns outros prós se fazem mais sutis, porém importantes, no de criar recursos extra ou de criar funcionalidades de forma errada.
ciclo de vida do software bem como na adesão de produtividade Até hoje, o BDD não tem recebido tanta atenção na comunidade de
ao projeto, tais como a diminuição do tempo usado para depurar pesquisas, mas isso provavelmente tenha relação com a sua idade
código, o que implicará no lucro de tempo e, consequentemente, e sua origem de método de pesquisa, o TDD, que ainda é alvo de
dinheiro. Tudo isso é possível pelo simples fato de o TDD informar muito contradição.
a quem o usa sempre que um erro ocorrer no sistema, diminuindo Ok, podemos dizer que entendemos o que é BDD. Mas, é ainda
o tempo de depuração e deixando-a menos custosa. brota algumas clássicas e famosas confusões. Alguns dizem que
o BDD é similar ao TDD (fato que justifica ainda mais o porquê
BDD de uma ter surgido a partir da outra), alguns outros irão dizer
O BDD foi primeiramente introduzido por Dan North no seu que é o mesmo que TDD porém com alguns guidelines melho-
artigo “Instrução ao BDD” e é uma metodologia que evoluiu res, ou ainda que são abordagens totalmente diferentes para o
das práticas de TDD. BDD é uma técnica de design sobre user desenvolvimento.
stories, que deve ser escrita em uma linguagem inteligível por Independente da definição, isso não importa muito. A principal
não-programadores. Isso possibilita que todos os envolvidos no coisa a se saber é que o “BDD é feito para eliminar problemas que
projeto, executivos, testers, usuários e outros funcionários a se o TDD venha a causar”.
tornarem mais ativos no desenvolvimento. As user stories são Em contraste ao TDD, o BDD consiste em escrever comportamen-
centradas na seguinte sintaxe: to e especificação que então dirija o desenvolvimento do nosso
software. Comportamento e especificação devem ser vistos como
Título (uma linha descrevendo a história) similares para testes mas a diferença é deveras importante.
Narrativa: Vejamos, então, novamente o problema descrito na seção anterior,
Como um(a) [regra] quando falávamos sobre TDD, sobre escrever uma função para
Eu quero [funcionalidade] calcular o valor fatorial de um número (Listagem 4).
Que então [beneficia] A principal diferença é somente a escrita. O BDD usa um estilo
mais verboso então isso pode ser lido quase como uma sentença.
Critério de aceitação: (apresentado como cenários) Isso é o mesmo que dizer que o BDD elimina problemas que o
TDD venha a causar. A habilidade de ler seus testes como uma
Cenário 1: Título sentença é uma maneira mais cognitiva de como podemos pensar
Dado um [contexto] e [mais alguns contextos]... acerca dos mesmos testes. O argumento atua no “se você pode ler
Quando [evento] seus testes fluidamente, você naturalmente irá escrevê-los de uma
Então [saída] e [outras saídas]... forma melhor e mais compreensiva”.
Apesar de esse exemplo ser muito simples e não ilustrar totalmente
Como ocorre com o TDD, BDD é uma técnica de design outside- isso, os testes BDD devem estar focados nas funcionalidades, e
in. No BDD as histórias são escritas primeiro, então verificadas e não nos resultados (essa também é uma das principais diferenças
priorizadas pelos usuários e envolvidos não-técnicos. O progra- entre os dois). Frequentemente, você ouvirá que o BDD existe para
mador então cria o código para atender às histórias descritas. Em ajudar no design do software, e não testá-lo como o TDD é suposto
BDD, existem três princípios-base: de fazer.
• Negócio e tecnologia devem referenciar o mesmo sistema da
mesma forma; BDD
• Qualquer sistema deve ter um valor identificado e variável DDD, ou Domain-Driven Development, é um conjunto de padrões
para o negócio; e métodos que focam na elaboração de aplicações que se caracte-

30 Front-end Magazine • Edição 02


rizam por refletir a cobrança compreendida e satisfatória de um Alguns defendem que o BDD é sempre melhor que o TDD por-
negócio qualquer. Analisando sobre outra ótica, ele constitui uma que ele tem a possibilidade de eliminar problemas que possam
inovação na forma de formar qualquer pensamento sobre a prática aparecer quando do uso do TDD.
de desenvolvimento e seus métodos. O DDD lida com a construção A chave para o BDD é que ele pode prevenir esses problemas;
de uma espécie de molde da realidade por inicialmente entendê-la isso não é garantido. Problemas como má organização do código,
por completo e só depois pôr terminologia, regras e meio lógico más práticas de design, etc. sempre irão persistir. Você deixará
juntos de forma abstrata no código fonte, o que comumente se de ter de escrever testes ruins e em contrapartida terá funciona-
chama de modelo de domínio. Não constitui nenhum framework lidades mais robustas.
ou ferramenta, mas sim uma espécie de plugin conceitual que pode Particularmente, nenhum dos estilos é melhor que o outro, isso
ser acoplado ao projeto em qualquer momento. realmente depende da situação, e de quem usa. Alguém que sabe
como escrever ótimos testes TDD pode ter alguns problemas como
Listagem 4. Resultado de comando de execução do Java version alguém que sabe escrever ótimos testes BDD. Se você se pegar
escrevendo testes incompletos usando TDD e quiser um design
var assert = require(‘assert’), fatorial = require(‘../index’); de software melhor, então dê uma chance ao BDD.
describe(‘Teste’, function (){
before(function(){ Ainda mais processos
// Coisas a se fazer antes dos testes, como importações Existem ainda algumas outras terminologias usadas para classi-
}); ficar outras vertentes de teste usadas como processos nos projetos
ágeis. Vejamos algumas delas abaixo:
describe(‘#fatorial()’, function (){
test(‘igual a 1 para configurações de tamanho zero’, function (){ • FDD – Feature Driven Development (Desenvolvimento Guiado
assert.equal(1, fatorial(0)); por Funcionalidades): O FDD é um tipo de teste feito para manter
}); e criar projetos por intermédio de uma lista de atividades simples,
de forma a incentivar o desenvolvimento de novos códigos, bem
test(‘igual a 1 para configurações de tamanho um’, function (){
como compartilhar o conhecimento acerca dos mesmos. Isso per-
assert.equal(1, fatorial(1));
}); mite, então, a principal meta do FDD seja alcançada no ciclo de
vida do software: resultados contínuos, funcionais e tangíveis.
test(‘igual a 2 para configurações de tamanho dois’, function (){ • ATDD – Acceptance test-driven development (Desenvolvimento
assert.equal(2, fatorial(2));
Guiado por Testes de aceitação): Conforme falamos anteriormente,
});
esse tipo de teste comumente é confundido com os testes do tipo
test(‘igual a 6 para configurações de tamanho três’, function (){ TDD, por causa da similaridade com que o desenvolvimento ágil
assert.equal(6, fatorial(3)); associa os testes de aceitação aos mesmos. Nesse tipo de teste, o
}); trabalho está totalmente direcionado aos testes de aceitação, o que
});
significa que pode haver uma analogia entre este e o TDD.
after(function () {
// Qualquer coisa a se fazer depois dos testes serem finalizados Quando escrever testes unitários?
}); Nós já discutimos inúmeros conceitos relacionados à utilização
});
dos testes unitários até aqui. Talvez a pergunta mais pertinente
que possa surgir nesse momento, antes mesmo de entender e
O DD pode ser entendido também como uma forma de auto- aceitar todos os conceitos até então apresentados, seja: Por que eu
matizar um negócio e seus processos, de forma que estejamos devo escrever testes unitários? Quando devo fazer isso?
sempre focados no software em si para que só assim o negócio Alguns desenvolvedores lidam com esse processo como mais
seja atendido por completo. uma prática chata a ser seguida dentro dos processos de uma
É comum, inclusive, associar o desenvolvimento de softwares empresa. Mais ainda, talvez antes de se fazer tais perguntas, sejam
corporativos a essa ideia em específico, mas o DDD vai além necessários antes um contato inicial com o ato de escrever testes.
e mostra formas e padrões de conceitualizar tudo isso em um Somente assim, você terá insumo suficiente para discernir se deve
modelo de domínio. ou não escrever testes de unidade, e aí, então, teremos a primeira
pergunta respondida. Mas e quanto ao “quando”?
TDD x BDD É fácil para um gerente semi técnico dizer “escreva todos os
A situação de ter de escolher entre TDD e BDD é complicada. testes do início” (em alguns casos, dizer isso pra você mesmo
Isso depende de haver ou não um framework de testes apropriado será tão fácil quanto), mas a verdade é que você frequentemente
para a sua linguagem escolhida, o que os seus colegas de trabalho não saberá quais são os pequenos componentes que são neces-
sentem em relação ao mesmo, e dependendo da situação muitos sários quando apresentados juntos a um caso de uso de nível
outros fatores entram na contagem. considerável.

Edição 02 • Front-end Magazine 31


Testes unitários em JavaScript: Introdução - Parte 1

É comum, por exemplo, que desenvolvedores façam os seus C# ou PHP, sendo considerada referência como linguagem, o
testes à medida que se vai desenvolvendo o código, à medida que JavaScript ainda tem muito a evoluir junto a suas companheiras
todos as “unidades” requeridas para implementar o caso de uso de lado (client side).
são feitas. Ao mesmo tempo, você estará constantemente mudan- É muito fácil, e comum, ignorar testes unitários quando se em-
do funções sobre esse código, refatorando e abstraindo também barca em um projeto de grande escala que faz uso de JavaScript.
algumas partes, e tentando se antecipar ao que possivelmente irá Muitas vezes motivados pelo grande costume de desenvolver
causar perda de tempo durante esse processo. testes apenas no lado do servidor, uma vez que muitas das
Consideremos o seguinte cenário: “como um usuário, ao logar regras de validação são sempre duplicadas em ambos os lados
na aplicação você será levado para uma tela de menu principal”. cliente e servidor. Porém, a necessidade de construir testes de
Como podemos quebrar essa operação genérica em unidades? unidade para JavaScript é tão real quanto com quaisquer outras
Imediatamente podemos selecionar o “login de formulário” linguagens. As ferramentas e procedimentos de testes unitários,
como uma implementação desse caso de uso que pode ser por sua vez, não são tão claros para JavaScript quanto para as
testada, e iremos adicionar algumas linhas de código de teste demais linguagens, o que acaba por construir uma imagem
requeridas para implementar essa funcionalidade corretamente mais defensiva dos programadores para com o teste usando a
(Listagem 5). linguagem de script.
O JavaScript vem de uma longa caminhada contra muitos con-
Listagem 5. Exemplo de divisão dos passos para realizar o teste unitário ceitos, e anticonceitos. Houve um tempo onde ele era facilmente
descartado, talvez adequado para validações não-críticas, mas
describe(‘login usuário’, function() {
// crítico
não mais que isso. Ao longo dos anos, o pior obstáculo que pro-
it(‘garanta que os endereços de email inválidos serão pegos’, function() {}); gramas feitos em JavaScript enfrentavam era sempre escrever
it(‘garanta que os endereços de email válidos irão passar da validação’, aplicações em larga escala, ou ao menos mitigáveis. Com o tempo,
function() {});
it(‘garanta que o formulário de submissão modifique o caminho padrão’,
os dialetos JavaScript foram ficando mais consistentes entre os
function() { }); browsers do que eram antes, e ferramentas como o jQuery podem
ajudar a deixar essas diferenças (que ainda existem) ainda mais
// é bom ter...
it(‘garanta que o helper client-side helper seja exibido para campos vazios’, leves aos olhos dos desenvolvedores. Os debuggers finalmente
function() { }); alcançaram melhores patamares de qualidade, jamais vistos
it(‘garanta que ao pressionar enter no campo de senha envie o formulário’, antes (sim, debugar JavaScript era terrível), atraindo, assim, o
function() { });
}); que antes afastava.

Nota
Dependendo das restrições implementadas, você deve decidir
O debug se tornou melhor ao longo do tempo, mas ainda depende do browser usado, pois cada
se deve ou não pular alguns passos, mas felizmente é possível
fabricante define suas próprias ferramentas de depuração.
ver com facilidade o quão crítico são cada um deles, isto é, que se
eles falharem podem bloquear o uso da aplicação.
Um outro exemplo clássico alusivo é o da construção de um Para todos os casos, com o advento da HTML5 e das plataformas
carro. Para construir um carro do início ao fim, cada parte que mobile, o JavaScript está se tornando cada vez menos ignorável.
faz a motor, o chassi, os pneus, devem ser verificados individu- Aplicações front-end inteiras estão sendo desenvolvidas em
almente para estar em ordem antes que elas possam de fato ser JavaScript, e enquanto a ferramenta suporta defasagens antes
atreladas ao carro. escondidas em linguagens como Java e C#, isso significa que
Se o tempo for dito insuficiente para averiguar todas estas temos evoluído.
peculiaridades, então possivelmente peças importantes serão E dentro desse escopo, uma área que permanece particularmente
despriorizadas e poderão não estar funcionando corretamente. mudando, e que irá começar a ficar incrivelmente importante nos
Por exemplo, os pneus podem acabar não sendo verificados em projetos JavaScript de escopo crescente são os testes unitários.
relação à pressão, a costura interior pode não ser verificada contra Para ilustrar uma situação mais próxima da programação, ve-
danos. Isso pode resultar em um carro falho, mas isso não seria seu jamos um exemplo de função básica em JavaScript, conforme o
problema, aparentemente. Apenas uma dica: verifique com cautela código a seguir:
o que pode ou não ser deixado de lado no momento de testar.
function addQuatroAoNumero(num){
Teste Unitário em JavaScript return num + 4;
Essa é uma história de controvérsias e recente. Apesar de }
JavaScript já ocupar espaço considerável na comunidade de
desenvolvimento front-end, inclusive até quando comparada a A mesma função basicamente adiciona o valor 4, como um nú-
outras linguagens de programação mais famosas como o Java, mero, à variável passada por parâmetro. Na Listagem 6 podemos

32 Front-end Magazine • Edição 02


verificar então um possível caso de teste para uma função de que framework escolher pode afetar profundamente as suas
execução. capacidades de testes.
Após passar o valor 5 para a função sendo testada, o teste checa Vejamos pois alguns dos frameworks mais famosos para Java-
que o valor retornado é 9. Se o teste suceder, a mensagem “Passou!” Script, bem como suas particularidades que ajudarão a analisar
é impressa no console de um browser moderno, caso contrário, a quando adotar um ou outro.
mensagem “Falhou!” aparecerá. Para executar este exemplo, você
precisará efetuar dois passos básicos: Listagem 6. Caso de teste para a função addQuatroAoNumero()
1. Importar o arquivo js que contém o código apresentado nas
(function testAddQuatroAoNumero (){
duas listagens anteriores. var num = 5, valorEsperado= 9;
2. Abrir a página da Listagem 7 no browser.
Ao invés de usar o console do browser para exibir os valores, você if (addQuatroAoNumero (num) === valorEsperado) {
console.log(“Passou!”);
pode imprimir os mesmos dentro da página ou dentro de uma } else {
janela pop-up através da função “alert()” do próprio JavaScript. console.log(“Falhou!”);
Dentro do universo de teste unitário, os elementos usados para }
}());
verificar se certa condição é satisfeita são chamados de “asser-
tions” (afirmações). Na Listagem 6 o assertion está concentrado Listagem 7. Página HTML para execução do exemplo
na operação:
<!DOCTYPE html>
<html>
addQuatroAoNumero (num) === valorEsperado <head>
<meta http-equiv=”Content-type” content=”text/html; charset=utf-8”>
<title>Exemplo Teste Unitário JavaScript</title>
Para os casos em que se tem muitos assertions sendo feitos, é <script type=”text/javascript” src=”js/script.js”></script>
interessante fazer uso de um framework de teste unitário JavaS- </head>
<body></body>
cript para auxiliar. </html>

Escolhendo um Framework
Se você desenvolve com Java, você provavelmente não perde qUnit
muito tempo decidindo que framework de teste unitário irá O qUnit é um ótimo candidato para começar. Antes de tudo,
usar. O mais famoso deles, o jUnit, é sempre a opção preferida ele é consideravelmente fácil de aprender. De início pode ser um
da maioria dos desenvolvedores por razões óbvias de quali- pouco complicado para entender alguns comportamentos que
dade. O panorama do JavaScript não é tão resolvido assim, e

Edição 02 • Front-end Magazine 33


Testes unitários em JavaScript: Introdução - Parte 1

são menos intuitivos, mas assim que se entende os problemas design. O JavaScript tem, como melhor, começado a desenvolver
por trás destes comportamentos tudo começa a fluir mais rapi- essa disciplina, e algumas das funcionalidades da linguagem
damente. Ele possibilita interação com o DOM; você pode, por que empurram os desenvolvedores Java na direção certa (como
exemplo, identificar uma DIV na sua página de teste para ser encapsulamento) não gozam do mesmo nível de suporte nativo
resetada para seu estado original entre os testes, promovendo no JavaScript.
assim atomicidade aos testes. Além disso, ele também provê su- Existem alguns frameworks que podem ajudar na escrita de
porte a “testes assíncronos”, o que constitui uma funcionalidade testes unitários. O ExtJS, por exemplo, põe um sistema de classes
vital para suas aplicações. no topo do modelo de objetos do JavaScript. Ferramentas como
essa podem ajudar se você as permitir, porém como elas não fa-
js-test-driver zem parte da linguagem, você pode sempre escolher ir contra as
O js-test-driver foca no teste paralelo em múltiplos browsers. mesmas. Escrever JavaScript testável é, e para o futuro continuará
Ele tem sua própria linguagem de casos de teste e assertions, sendo, uma arte a ser modelada de acordo com a prática.
distinta do qUnit. Existem projetos que possibilitam ambos Não é algo simples manter sempre o foco na testabilidade.
de serem usados juntos, apesar de não existir um que suporte Mesmo que você programa todas as linhas do seu código com os
todas as capacidades de ambos frameworks. Diferente do qUnit, olhos voltados para a testabilidade do mesmo, sempre aparecerão
ele não usa partes do DOM para relatar resultados e reinicia o determinados comportamentos no código que fugirão à regra,
DOM inteiro entre um teste e outro. Isso impõe uma restrição como ubiquidade ou comportamentos assíncronos. Todo motor
a ser testada. JavaScript é single-threaded, mesmo que algumas tarefas simples
como requisitar um dado do servidor (usando Ajax, por exemplo),
Ambiente de Execução dos Testes respondendo à chamada UI, ou explicitamente retardando uma
Essa é outra questão que parece muito mais complicada com atividade (através de um setTimeout ou setInterval), são todas
JavaScript do que com Java: em qual ambiente devo executar feitas assincronamente.
meus testes? Então, o que um executor de testes deve fazer? Você é chamado
Você deve sempre querer que o seu ambiente de teste seja com- a agrupar o código que está testando.
patível com o ambiente de produção o mais próximo possível. 1. O framework é configurado para executar os testes;
Mas para muitas aplicações JavaScript, um pedaço crítico desse 2. O código de teste configura pré-condições e faz uma chamada
ambiente, o browser com seu respectivo motor JavaScript, é esco- para o código a ser testado;
lhido pelo usuário. Mesmo se os problemas cross-browser (vários 3. O código de teste checa os assertions;
browsers) não forem tão ruins quanto eles eram antes, ainda é 4. O framework reporta os resultados e vai para o próximo tes-
muito imaturo dizer que um teste feito em um browser terá um te.
resultado consistente por além dos demais.
Ao mesmo tempo, testar em todos os diferentes browsers traz Mas e se o código a ser testado faz alguma coisa de forma
mais desafios quando você começar a pensar em testes automa- assíncrona? Então, podemos verificar alguns outros passos
tizados e CI. Esse é o grande desafio que o js-test-driver é desig- específicos:
nado a resolver. Se você quer uma solução puramente qUnit, você 1. O framework é configurado para executar os testes;
provavelmente irá encontrar por si só escrevendo seus próprios 2. O código de teste configura pré-condições e faz uma chamada
scripts ou fazendo sem automação. para o código a ser testado;
Existem vários ambientes de execução JavaScript com suporte 3. O código a ser testado inicia algo, e então ele chama alguma
fácil a scripts, como o NodeJE, por exemplo, que será muito útil função para finalizar a tarefa;
para alguns testes automatizados de alto nível. Porém, eles terão 4. O framework reporta (imprecisamente) os resultados e vai para
suas próprias limitações (NodeJS não tem suporte a DOM nativo, o próximo teste;
apesar dos add-ons existirem) e em todo caso não conseguirá 5. Outras funções de fila devem executar;
simular o comportamento do browser. 6. A parte em fila do código a ser testada recebe sua vez de exe-
Uma abordagem multicamada deveria se aplicar melhor às suas cutar, e finaliza a coisa toda que foi iniciada no passo 3;
necessidades. Você poderia criar alguns scripts de teste para 7. O código de teste verifica os assertions.
executar no NodeJS por CI, e então rodar periodicamente uma
suíte de testes em cada browser alvo. Alguns bugs deverão não Dessa forma você consegue uma porção de testes falhando por
ser pegos como seriam se usasse uma CI completa. uma razão não muito boa.
O qUnit endereça isso com a função asyncronousTest(). Isso
Estrutura do Código funciona apenas como a função regular test(), exceto pelo fato
Nos primórdios do jUnit, não era incomum encontrar código Java do framework não assumir que o teste está finalizado quando o
que não se dirigisse diretamente aos testes unitários. Ao longo dos código de teste retorna. Você deve informar a ela quando o teste
anos, isso passou a ser visto como um teste de qualidade de um está finalizado chamando a função start().

34 Front-end Magazine • Edição 02


Esse tipo de comportamento soa um pouco retrógrado. Você com o tempo e o acúmulo de situações durante a vida como
chama a função start() quando você precisa finalizar o teste, por- desenvolvedor.
que isso diz ao framework para reiniciar o processamento. Esse Teste unitário para JavaScript, então, é mais complicado de
mecanismo inteiro faz com que os testes executem em lockstep, o assimilar principalmente em vista do histórico que a linguagem
que parece que é síncrono, mas você pode chamar asyncronous- traz consigo, não sendo considerada por muito tempo sequer
Test() porque o nome referencia a natureza assíncrona do código para programação básica, no até então advento das tecnologias
sendo testado. server side.

Objetos Mock Autor


A natureza dinâmica do JavaScript traz, por sua vez, vários
benefícios e flexibilidades para escrever objetos mock, mesmo Sueila Sousa
usando um framework de objetos mock. Tester e entusiasta de tecnologias front-end. Atualmente
Em Java, o seu objeto mock tem que compartilhar uma interface trabalha como analista de testes na empresa Indra, com foco
com, e/ou ser uma subclasse de, a classe que o substitui. Depen- em projetos de desenvolvimento de sistemas web, totalmente
baseados em JavaScript e afins. Possui conhecimentos e experiências
dendo da sofisticação do seu framework mock, isso pode impor
em áreas como Gerenciamento de processos, banco de dados, além do
várias restrições e/ou fazer com que o desenvolvedor pule alguns interesse por tecnologias relacionadas ao desenvolvimento e teste client side.
passos para ir direto ao trabalho pronto. Em JavaScript, você pode
criar um objeto que implemente exatamente o mesmo compor-
tamento do mock. De certa forma isso também ajuda se o seu Links:
código tiver sido escrito com algum tipo de inversão de controle
embutida, caso contrário ao menos você irá se beneficiar com a Site do W2Schools, mantenedor do JavaScript
www.w3schools.com/js/
forma fácilo de interceptar uma função chamada no JavaScript.
Desenvolver código unitário não é uma tarefa simples, tampou- Página oficial do qUnit
co personalizável e imediatista como muitos desenvolvedores a www.qunitjs.com/
consideram. Exige conhecimentos acerca do processo, técnicas e
Página do projeto do JS Test Driver
intimidade com as ferramentas e processos envolvidos. Existe, www.code.google.com/p/js-test-driver/
sobretudo, experiência que, por sua vez, só pode ser adquirida

Edição 02 • Front-end Magazine 35


Testes unitários em JavaScript: Introdução - Parte 1

36 Front-end Magazine • Edição 02

Você também pode gostar

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy