O que fazer quando seu codigo JavaScript se torna um monstro
Quando eu não conhecia jQuery e seus plugins, JavaScript era um tédio pra mim. É fato que uma biblioteca de alto nível (não só o jQuery, mas o mootools e o prototype, por exemplo) facilitam e deixam o desenvolvimento em JavaScript rápido e divertido, pois você não terá que se preocupar (muito) com detalhes de implementação de browsers.
Mas o que acontece quando, mesmo usando com alguma lib fodástica, seu código começa a ficar grande demais, complexo demais, fragmentado demais ou desorganizado demais? Isso é a minha definição de código monstro. Eis algumas dicas que podem te ajudar se você estiver passando por isso:
1 - Evite o Callback Hell
O jQuery mostra muitos exemplos usando funções anônimas como callback. De certo modo, isso é uma boa prática para situações simples, como o tratamento do evento clique de um botão:
$("#meuBotao").click(function(){
alert('Fui clicado!');
});
Mas nem sempre isso é legal: muitas vezes você quer reaproveitar essa função para outros callbacks, como por exemplo:
$('#meuBotao').click(getClientes);
$('#meuInput').blur(getClientes);
getClientes = function()
{
$.get('/clientes/get','',
function(data){
//trata os dados recebidos aqui
},'json')
}
Nesse caso, eu estou aproveitando minha função de callback getClientes para dois event listeners. Isso é bem legal, mas quando nosso código começa a crescer, nos esbarramos em outro problema: as funções globais.
2 - Evite funções globais
Isso quer dizer, ao invés disso:
$('#meuBotao').click(getClientes);
$('#meuInput').blur(getClientes);
getClientes = function()
{
$.get('/clientes/get','',
function(data){
//trata os dados recebidos aqui
},'json');
};
Faça algo assim:
$('#meuBotao').click(getClientes);
$('#meuInput').blur(Clientes.getClientes);
var Clientes = {
getClientes:function()
{
$.get('/clientes/get','',
function(data){
//trata os dados recebidos aqui
},'json');
}
};
Isto é, coloque suas funções dentro de objetos. Assim você evita funções globais e evita fazer código "estruturado", passando a usar os recursos da orientação à objetos do JavaScript e deixando o mínimo de globals possível. Essa é a forma mais fácil que eu conheço de se evitar funções globais e organizar melhor seu código, mas há outras formas como o Module Pattern.
3 - O "this" aponta para diferentes lugares em diferentes contextos. Saiba como lidar com isso.
Você não está deixando mais todas as suas funções como globais, está encapsulando tudo dentro de objetos, reaproveitando código e feliz da vida quando percebe que o this não é mais this. Calma que eu explico.
Você já deve ter visto algo assim no jQuery:
$('a').click(function(){
$(this).html('fui clicado') ;
});
Isso faz com que, quando um link é clicado, o mesmo fique com o texto "fui clicado". Deu pra notar que nesse caso, o this aponta para o elemento que disparou o evento. Mas olhe o seguinte exemplo:
var Cliente =
{
texto:'Fui clicado',
init:function()
{
$('a').click(this.aClickHandler); //this aponta para o objeto Cliente
},
aClickHandler:function()
{
$(this).html(Cliente.texto); //this aponta para o elemento "a" que disparou o evento
}
};
Viu como "this" pode mudar de contexto? No exemplo acima, o problema de não ter o this apontando para o objeto Cliente foi facilmente contornado, mas você poderá precisar acessar o objeto pai de uma forma parecida com a this. Nesse caso, você pode passar um parâmetro para o evento usando o método bind() do jQuery, informando o contexto que ele foi chamado:
var Cliente =
{
texto:'Fui clicado',
init:function()
{
$('a').bind('click',{'self':this},this.aClickHandler); //this aponta para o objeto Cliente
},
aClickHandler:function(event)
{
var self = event.data.self;
$(this).html(self.texto); //o self aponta para Cliente e o this aponta para o elemento "a" que disparou o evento
}
};
4 - Procure pelos patterns corretos.
Quem disse que padrões de projeto criam um vocabulário em comum na equipe não poderia ter dito algo mais pertinente: o uso de padrões faz com que o desenvolvedor foque nas funcionalidades da aplicação sem se preocupar com alguns detalhes de implementação.
O AjaxPatterns contém uma coleção bem legal e bem documentadas de patterns para Ajax e JavaScript em geral. Mas não espere ter problemas pra consultar os patterns: quanto mais se conhece sobre padrões, mais fácil é pensar em soluções de problemas e planejamento em geral.
5 - Deixe apenas um $(document).ready em todo o seu código
Eu diria isso para todos os event listeners que você possa vir a colocar, mas o $(document).ready é o mais crítico na minha opinião. No JavaScript não há sobreposição de eventos: se você colocar dos event listeners para um mesmo evento, os dois serão executados. Isso pode dar problemas, pois você pode deixar o $(docuement).ready em dois arquivos diferentes e você pode desejar que um evento execute antes de outro.
6 - Valide seu JavaScript
Browsers interpretam JavaScript de forma diferente, então é sempre bom ter uma padronização de código para que não tenhamos problemas com sintaxe em diferentes browsers. Uma ferramenta de validação bem legal é o jslint.
Criando Web crawlers em Python – Parte II
No post anterior, eu mostrei como recuperar informações básicas de uma página da Web usando urllib, urllib2 e BeautifulSoup. Neste post eu mostrarei como enviar dados via GET e POST.
Há um excelente guia sobre urllib2: o urllib2 - The Missing Manual que foi de grande valia nos meus estudos. Nele, pode-se encontrar as informações sobre envio de informações do tipo GET e POST para o servidor. Isso será útil, pois é assim que a busca do SourceForge (e da maioria dos outros portais) funcionam.
Vamos dar uma olhada na URL do na pesquisa por "Python" no SF:
http://sourceforge.net/search/?type_of_search=soft&words=python
Bem, isso indica que temos que enviar duas variáveis para o SF.net: type_of_search (sempre igual à soft) e words (que é a nossa busca). Um exemplo de código que faria essa busca poderia ser esse:
import urllib,urllib2
base_url = 'http://sourceforge.net'
busca = raw_input('Pesquisar por: ')
variaveis_get = urllib.urlencode({'type_of_search':'soft','words':busca})
req = urllib2.Request(base_url+'/search/',variaveis_get)
response = urllib2.urlopen(req).read()
print response
Se der tudo certo, você deveráver o código fonte da página do SF que contém os resultados da pesquisa.
Feito isso, vamos analisar como a marcação do SF é organizada na busca:
O Firebug nos ajuda a não perder tanto tempo assim analisando código. De acordo com o que pudemos obter, podemos dividir as informações que queremos dessa forma:
- O resultado da busca está dentro de uma tabela com o id="searchtable".
- Um resultado da busca está sempre dentro de um td com classe description.
- O nome do projeto está dentro de um link dentro de um h2 dentro desse td "description".
- O link de download se encontra na próxima td da mesma linha da tabela.
Exibindo as informações dos projetos
Agora nós temos como buscar nossa informação e como filtra-la. Como disse no post anterior, eu iria mostrar alguns usos mais avançados do BeautifulSoup, principalmente no que diz respeito à percorrer o documento. O próximo passo será mostrar as informações dos projetos que aparecem no resultado da nossa busca. Podemos fazer isso da seguinte forma:
from BeautifulSoup import BeautifulSoup
import urllib,urllib2
base_url = 'http://sourceforge.net'
busca = raw_input('Pesquisar por: ')
variaveis_get = urllib.urlencode({'type_of_search':'soft','words':busca})
req = urllib2.Request(base_url+'/search/',variaveis_get)
response = urllib2.urlopen(req).read()
soup = BeautifulSoup(response)
tabela = soup.find('table',{'id':'searchtable'}) # procura pela tabela com id=searchtable
linhas_tabela = tabela.findAll('tr') #retorna uma lista com todas as linhas (<tr>) da tabela
i=0
for linha in linhas_tabela:
i+=1
coluna_descricao = linha.find('td') #encontra a primeira coluna (descricao) da linha
nome_projeto = coluna_descricao.find('a').contents[0] #o atributo contents contem uma lista com o conteudo da tag
descricao_projeto = coluna_descricao.contents[2].strip()
print 'Projeto '+str(i)+': '+nome_projeto
print descricao_projeto
print '--------------------------------'
Legal, não? Isso é uma demonstração básica do poder que o BeautifulSoup tem para percorrer e extrair informações em (X)HTML. O mais interessante de tudo é que quase todos os métodos da classe BeutifulSoup.Tag retornam a própria referência, o que quer dizer que podemos fazer chains (cadeias) de comando como essas:
nome_do_primeiro_projeto_da_pesquisa = soup.find('table',{'id':'searchtable'}).findAll('tr')[0].find('td').find('a').contents[0]
Isso é realmente muito útil quando se quer economizar código. E o mais interessante de tudo: é bem legível (mas não necessariamente fácil de interpretar... quem ler seu código assim terá que ter uma boa noção do BeautifulSoup).
Baixando os arquivos do projeto
Essa parte é relativamente fácil. O SF é um serviço muito bom, até para o nosso pequeno experimento
A URL que o link "Download Now" aponta sofre 3 redirects até o arquivo final. Tudo isso serve para o SF determinar a sua localização e apontar o mirror mais próximo de você. Então a única coisa que precisamos fazer é passar esse link para o wget (um programa bem útil para download de arquivos na Web presente na maioria das distribuições Linux. Um clone para Windows pode ser encontrado aqui) e ele irá baixar o projeto para nós. Simples, não?
Então vamos ao código:
from BeautifulSoup import BeautifulSoup
import urllib,urllib2
from subprocess import call
base_url = 'http://sourceforge.net'
busca = raw_input('Pesquisar por: ')
variaveis_get = urllib.urlencode({'type_of_search':'soft','words':busca})
req = urllib2.Request(base_url+'/search/',variaveis_get)
response = urllib2.urlopen(req).read()
soup = BeautifulSoup(response)
tabela = soup.find('table',{'id':'searchtable'}) # procura pela tabela com id=searchtable
linhas_tabela = tabela.findAll('tr') #retorna uma lista com todas as linhas (
) da tabela
i=0
links_download = []
for linha in linhas_tabela:
i+=1
coluna_descricao = linha.find('td')
nome_projeto = coluna_descricao.find('a').contents[0]
link_download = linha.find('a',{'class':'downloadnow'})['href']
links_download.append(link_download)
descricao_projeto = coluna_descricao.contents[2].strip()
print 'Projeto '+str(i)+': '+nome_projeto
print descricao_projeto
print '--------------------------------'
opcao = int(raw_input('Qual projeto gostaria de baixar? '))
opcao_url = base_url+links_download[opcao-1]
call(['wget',opcao_url]) #chama o wget com o link para download
A única coisa que eu fiz de novo foi adicionar o link de download em uma lista e perguntar ao usuário qual projeto ele deseja baixar. Então, eu passei o link de download para o wget que fez o serviço de baixar o arquivo pra mim. Pronto! Nosso crawler de exemplo do SF.net está pronto
No proximo post eu mostrarei como guardar valores de sessão para percorrermos páginas protegidas por senha. See ya!
Minicurso de jQuery na Unimontes. Reserve ja a sua vaga!
Era pra eu ter postado isso aqui antes, mas ainda há tempo.
A comissão de formatura do 7º período de SI da Unimontes (a qual eu me incluo) está organizando um minicurso de 12 horas de jQuery. Serão duas turmas com 20 vagas: uma durante a semana (segundas e quartas-feira, de 19:30 às 21:30 - vagas esgotadas) e durante o sábado (8:00 - 12:00 - aproximadamente 10 vagas restantes).
O conteúdo a ser abordado será esse:
Criando Web crawlers em Python – Parte I
Ir para: Criando Web Crawlers em Python - Parte II
Iniciemos com a definição de Web crawler:
Um Web crawler é um programa de computador que navega pela World Wide Web de maneira metódica e automatizada. [Wikipedia]
Os Web crawlers (ou simplesmente crawlers) têm um papel importante na nossa vida hoje. Como exemplos clássicos de Web crawlers, podemos citar o Google Bot, o Yahoo! Slurp e o MsnBot. Sem esses crawlers, não teríamos a busca do Google, do Yahoo! ou do Bing.
O objetivo dessa série de tutoriais não é ensinar criar crawlers de alta disponibilidade, alta performance e distribuídos mas mostrar como eles podem ser construidos sem muito custo ou complexidade, de forma que atenda uma necessidade específica. Entenda necessidade específica como download de imagens de um conjunto de páginas, um sistema de download de arquivos de hosts como o Rapidshare ou MegaUpload (sim, é possível!) ou uma busca e categorização de informações distribuídas entre diversos sites (como editais de concursos em portais).
Aspectos legais e ética de crawlers:
Antes de continuar lendo esta série, gostaria de informar que não é todo site que lhe dá permissão de acesso por meios de robores de busca. Procure sempre ler as políticas de uso e sempre respeite o robots.txt: se não é pra você crawlear determinada página, não o faça.
O processo:
Preste atenção aos componentes do crawler:
- Fila: pode conter uma ou mais URLs. Dependendo do tamanho da fila, a mesma pode estar no disco, ao invés de somente na memória.
- Downloader: geralmente costuma-se colocar um downloader multithreaded. No nosso primero exemplo vamos fazer um downloader singlethreaded para evitar complexidade.
- Parser: esse é o mais interessante. Ele vai extrair informações da página baixada pelo downloader segundo as especificações passadas pra ele. É pra ele que você irá dizer que quer extrair todas as imagens de uma determinada página.
- Storage: pode ser qualquer tipo de armazenamento em qualquer tipo de mídia. Não iremos persistir os dados nessa primeira parte do tutorial.
Nota-se que esse diagrama não representa um crawler de alta performance, pois ele mal diz sobre a arquitetura do mesmo, não diz sobre hardware, links de rede, paralelismo e tudo mais, mas serve com o intuito de explicar o básico do sistema.
Maos à obra: fazendo um downloader com uma fila simples
Para download de páginas e arquivos na Web, nós usaremos o urlib e a urlib2 do Python. Apesar das versões das libs, uma complementa a outra. Por exemplo, só se pode mudar os headers HTTP na urllib2 e o método urlencode só está disponível na urllib. Contudo, nós usaremos mais a urllib2. O código:
import urllib2 url = "http://www.google.com" request = urllib2.Request(url) response = urllib2.urlopen(request) document = response.read() print document
Execute esse código e se tudo der certo você verá o código fonte da página inicial do Google!
Bem, só ter o código fonte da página não é muito útil. Precisamos extrair informações dela. Uma forma de que podemos adotar é por Regex (expressão regular), mas usar regex dificultaria nosso trabalho e fugiríamos da idéia de deixar as coisas simples.
Um grande problema da Web hoje é que muitos desenvolvedores escrevem código (X)HTML mal formado e isso dificulta um pouco nossa vida. Felizmente isso não é um impedimento grave e podemos contorna-lo com o BeautifulSoup. O BeautifulSoup faz um excelente trabalho transformando o código de marcação (HTML, XML ou XHTML) em objetos que podem ser facilmente manipulados. De acordo com o esquema mostrado apresentado aqui, o BeautifulSoup faz parte do parser.
Façamos algo útil: vamos listar todos os links da página inicial do Google.
import urllib2
from BeautifulSoup import BeautifulSoup
url = "http://www.google.com"
request = urllib2.Request(url)
response = urllib2.urlopen(request)
document = response.read()
soup = BeautifulSoup(document) #normaliza o documento para que o mesmo seja acessível via objetos
links = soup.findAll('a') # retorna uma lista com todos os links do documento
for link in links:
print link
Fácil não?!
Se tudo correr bem, você deve ver uma saída igual a essa:
<a href="http://images.google.com.br/imghp?hl=pt-BR&tab=wi">Imagens</a><a href="http://video.google.com.br/?hl=pt-BR&tab=wv">Vídeos</a><a href="http://maps.google.com.br/maps?hl=pt-BR&tab=wl">Mapas</a><a href="http://news.google.com.br/nwshp?hl=pt-BR&tab=wn">Notícias</a><a href="http://www.orkut.com/Home.aspx?hl=pt-BR&tab=w0">Orkut</a><a href="http://mail.google.com/mail/?hl=pt-BR&tab=wm">Gmail</a><a href="http://www.google.com.br/intl/pt-BR/options/" style="text-decoration:none"><u>mais</u> »</a><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA">iGoogle</a><a href="/preferences?hl=pt-BR">Configurações da pesquisa</a><a href="https://www.google.com/accounts/Login?hl=pt-BR&continue=http://www.google.com.br/">Fazer login</a><a href="/search?q=Vancouver+2010&ct=olympics10-sskating-hp&oi=ddle"><img src="/logos/olympics10-sskating-hp.png" width="523" height="170" border="0" alt="Vancouver 2010" title="Vancouver 2010" id="logo" onload="window.lol&&lol()" /></a><a href="/advanced_search?hl=pt-BR">Pesquisa avançada</a><a href="/language_tools?hl=pt-BR">Ferramentas de idiomas</a><a href="/intl/pt-BR/ads/">Soluções de publicidade</a><a href="/services/">Soluções empresariais</a><a href="/intl/pt-BR/about.html">Tudo sobre o Google</a><a href="http://www.google.com/ncr">Google.com in English</a><a href="/intl/pt-BR/privacy.html">Privacidade</a><a href="http://images.google.com.br/imghp?hl=pt-BR&tab=wi">Imagens</a><a href="http://video.google.com.br/?hl=pt-BR&tab=wv">Vídeos</a><a href="http://maps.google.com.br/maps?hl=pt-BR&tab=wl">Mapas</a><a href="http://news.google.com.br/nwshp?hl=pt-BR&tab=wn">Notícias</a><a href="http://www.orkut.com/Home.aspx?hl=pt-BR&tab=w0">Orkut</a><a href="http://mail.google.com/mail/?hl=pt-BR&tab=wm">Gmail</a><a href="http://www.google.com.br/intl/pt-BR/options/" style="text-decoration:none"><u>mais</u> »</a><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA">iGoogle</a><a href="/preferences?hl=pt-BR">Configurações da pesquisa</a><a href="https://www.google.com/accounts/Login?hl=pt-BR&continue=http://www.google.com.br/">Fazer login</a><a href="/search?q=Vancouver+2010&ct=olympics10-sskating-hp&oi=ddle"><img src="/logos/olympics10-sskating-hp.png" width="523" height="170" border="0" alt="Vancouver 2010" title="Vancouver 2010" id="logo" onload="window.lol&&lol()" /></a><a href="/advanced_search?hl=pt-BR">Pesquisa avançada</a><a href="/language_tools?hl=pt-BR">Ferramentas de idiomas</a><a href="/intl/pt-BR/ads/">Soluções de publicidade</a><a href="/services/">Soluções empresariais</a><a href="/intl/pt-BR/about.html">Tudo sobre o Google</a><a href="http://www.google.com/ncr">Google.com in English</a><a href="/intl/pt-BR/privacy.html">Privacidade</a>
Na verdade, a linha
links = soup.findAll('a')
não retorna uma lista de strings, mas uma lista de objetos que representam tags em HTML (classe BeautifulSoup.Tag). Logo, há outras propriedades e métodos que podemos explorar. Digamos que você só queira as URLs dos links e não está interessado no texto ou na marcação. O nosso código ficaria assim:
import urllib2
from BeautifulSoup import BeautifulSoup
url = "http://www.google.com"
request = urllib2.Request(url)
response = urllib2.urlopen(request)
document = response.read()
soup = BeautifulSoup(document) #normaliza o documento para que o mesmo seja acessível via objetos
links = soup.findAll('a') # retorna uma lista com todos os links do documento
for link in links:
print link['href']
Como saída, você pode obter algo do tipo:
http://images.google.com.br/imghp?hl=pt-BR&tab=wi http://video.google.com.br/?hl=pt-BR&tab=wv http://maps.google.com.br/maps?hl=pt-BR&tab=wl http://news.google.com.br/nwshp?hl=pt-BR&tab=wn http://www.orkut.com/Home.aspx?hl=pt-BR&tab=w0 http://mail.google.com/mail/?hl=pt-BR&tab=wm http://www.google.com.br/intl/pt-BR/options/ /url?sa=p&pref=ig&pval=3&q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA /preferences?hl=pt-BR https://www.google.com/accounts/Login?hl=pt-BR&continue=http://www.google.com.br/ /search?q=Vancouver+2010&ct=olympics10-sskating-hp&oi=ddle /advanced_search?hl=pt-BR /language_tools?hl=pt-BR /intl/pt-BR/ads/ /services/ /intl/pt-BR/about.html http://www.google.com/ncr /intl/pt-BR/privacy.html
Como você pode ver, o BeautifulSoup é quase uma mãe quando o assunto é extrair informações de HTML
.
No próximo tutorial, eu abordarei usos mais avançados do BeautifulSoup e mostrarei como usar os métodos GET e POST e também mostrarei uma pequena aplicação para procurar e baixar arquivos do SourceForge.net. Até o próximo!
Criando screencasts no Linux
Eu vi algumas pessoas reclamando sobre a dificuldade de criar screencasts usando Linux. É, eu também tive algumas dificuldades. Nenhuma das ferramentas que eu consegui encontrar com minhas buscas não resolviam meu problema:
- Istanbul - Bonitinho, parece leve, grava legal, mas simplesmente dá um erro de IO (não entendi direito qual era o erro ) e não salva.
- xvidcap - Levíssimo, completo, mas tem problema com o PulseAudio e não grava o áudio do microfone. Tentei inicializa-lo com o comando padsp xvidcap, mas também não resolveu: mesmo chiado no som.
- recordMyDesktop - Grava áudio normal, mas as imagens tinham uma qualidade horrível. Parecia que ele atualizava uma parte da tela e esquecia da outra. Resultado: eu gravava um teste no VIM na linha de comando (preta) e quando eu passava pro GMail (verde) a tela ainda continuava preta...
Não sei o por quê, mas nem todos os programas que vem no Linux vêm com as configurações mais comuns já de cara. O problema é que eu não percebi que o recordMyDesktop encaixaria perfeitamente pra mim se ele já viesse com uma opção já marcada desde o início:
Estranho, não? Eu pensava que marcar "Full shots at every frame" resolveria meu problema, mas, inexplicavelmente, o "Encode On the Fly" resolveu. Apesar da tooltip dizer que essa opção consome mais poder de processamento, eu não notei tanto. A qualidade do vídeo ficou impecável e eu estou com os efeitos no máximo
Se após gravado o screencast você desejar edita-lo ou converte-lo, há uma gama de softwares para Linux mesmo que fazem isso. Para conversão eu uso muito o ffmpeg (não conheço nenhum outro melhor e mais completo) e me recomendaram o Avidemux para edição de vídeo. A única coisa que eu sinto falta agora é algo que coloque os caracteres digitados na tela e que destaque o clique do mouse.
See ya!
Dica rapida: conversao de bases em JavaScript
Essa é uma dica extremamente simples mas que poderia ter salvo um tempo em um dos nossos CodingDojo. Trata-se de conversão de bases em JavaScript.
(14).toString(2) // decimal para binário. Saída: 1110 (0xf3).toString(10) //hexadecimal (início 0x) para decimal. Saída: 243 (0324).toString(16) //octal (inicio 0) para hexadecimal. Saída: d4 (15276).toString(36) // decimal para base 36 (máximo possível). Saída: bsc
Legal, não?
Créditos da dica: Elvis.
Flex For Kids foi 10!
Depois de um dia inteiro de correria, muita palestra e principalmente comida, estou aqui para contar um pouco do Flex For Kids para vocês.
Infelizmente, perdemos uma palestra que parecia ser bem legal: Desenvolvimento Multi-touch com AIR 2.0. Tivemos problemas com a conexão e iniciamos meio atrasados. Bem que a porta de saída poderia ser a 80 mesmo... evitaria muitos problemas.
Conseguimos pegar a palestra do Igor Musardo (Construa painéis administrativos em Flex integrados com ASP.NET MVC) bem no início, quando ele começou a falar sobre ASP.NET MVC e Flex. Ele mostrou um pequeno sistema para gerenciamento de conteúdo usando o Flex 3 e o ASP.NET MVC como backend e usou o JSON como formato de comunicação. A maioria dos presentes não tinha familiaridade com .NET, mas serviu pra mostrar um pouco da tecnologia. Bem interessante a palestra, mas eu fiquei curioso com o fato dele não usar AMF para isso. Devido à alguns problemas técnicos com a transmissão, a palestra do Musardo acabou atrasando um pouco, mas nada grave.
A palestra a seguir foi a do Mário Junior: Swiz Framework: MVC Simples e Poderoso para projetos Flex/AIR. Como o Mario mesmo disse, o Swiz é extremamente simples e leve, no entanto a palestra dele serviu para mostrar como eu subutilizo os recursos que o Swiz oferece. Ele é muito mais poderoso que eu pensava. Valeu muito pra mim e pra galera da Infobits. Muito boa a palestra dele.
Como eu estava na organização e nós tínhamos que trazer o almoço para a Unimontes, eu acabei perdendo a palestra do Eberton Consolim: Flex e VOIP: Adicione essa tecnologia em suas aplicações. Segundo a galera que assistiu, a palestra foi excelente, mas infelizmente terei que aguardar o acesso às gravações para ter certeza
A próxima palestra logo após o almoço foi a do Daniel Lopes: Desktop com HTML, Javascript e Adobe AIR. A palestra foi muito bem ministrada: muito conceito, muita idéia e pouca explicação de código e ele incrivelmente conseguiu fazer um hands-on sem muitas delongas. Incrível. Excelente palestra.
A palestra da Gabriela teria sido mais interessante se eu entendesse um pouco mais de User eXperience. No entanto, foi bom ter uma palestra no-code no meio de tantas. Aliás, foi bom ter visto uma mulher no meio de tanto marmanjo
. Mesmo assim, foi proveitosa.
O Eric Calvancanti assumiu a missão de desmistificar o Cairngorm. E posso dizer que ele o fez com muito sucesso! Segundo o Vedovelli, até a avó dele entenderia o que o Eric quis passar. Foi a apresentação mais didática que tivemos, apesar do Cairngorm ser o framework mais complexo apresentado hoje.
A palestra do Vedovelli foi uma das mais esperadas. Muito conhecido pelos seus screencasts e sua irreverência, o Ved, como costuma ser chamado, se tornou um dos ícones dos Flexers nacionais. Ele explicou como funciona a arquitetura de uma aplicação usando o framework Mate. O framework é interessante e comparável em muitos pontos com o Swiz. Muito boa apresentação.
O "vírus da bactéria" que o cachorro do Igor Costa não consegue ver deixou a sua apresentação muito divertida, além de informativa! O Igor é uma das maiores referencias em Flex e Java no Brasil e sua palestra foi memorável. Eu não saco muita coisa de JEE, mas a palestra dele foi bem inteligível.
E por último e com a melhor palestra do dia, a do Beck Novaes. Ele deu uma geral sobre a plataforma Adobe de desenvolvimento de RIAs: Flash, Flex, Flash Builder e Flash Catalyst. A palestra foi incrível. Ele tem um mix de explicação extremamente fácil de entender com informação útil. Deveria ter sido a primeira palestra do dia, com toda certeza.
Nossa reunião na Unimontes teve uma audiência de 15 pessoas e contou com a organização e apoio da Infobits e da Gerência de Tecnologia da Informação da Unimontes. Queria agradecer a todos que vieram e prestigiaram o evento. Também gostaria de dar os parabéns a todos que tiraram o escorpião do bolso e doaram para o Cotolengo. Muito bacana! A seguir, as fotos do evento:
Eu vou participar do Flex For Kids. E voce?
Como eu bloguei em outro blog anteriormente, eu vou participar do Flex For Kids!
Basicamente, o evento é praticamente uma maratona de palestras: nove palestras de uma hora cada em exatamente nove horas de duração, de 8:00 às 17:00, e contará com palestrantes da comunidade Flexer Brasiliera.
Todo dinheiro arrecadado com as inscrições será destinado à Cotolengo, uma instituição do Mato Grosso do Sul que acolhe pessoas com necessidades especiais.
Nós, da Infobits, conseguimos reservar o auditório do Centro de Ciências Exatas e Tecnológicas para acomodar os participantes do evento, estamos organizando algumas outras coisas (como o almoço, a alimentação no resto do dia e a inscrição no evento) e temos 8 pessoas já confirmadas (o número vai subir até amanhã).
Só lembrando: se você quer participar do Flex For Kids conosco, ainda tem tempo! Nos procure na Infobits*, mande email, sinal de fumaça ou comente esse post
*Sala 10A do Centro de Ciências Exatas e Tecnológicas. Perdido? Veja no Google Maps.
Testes unitarios no Flex usando o FlexUnit 4
O FlexUnit 4 é a mais nova versão (não tem a oficial, só a RC, por enquanto) e apresenta uma série de vantagens sobre o seu antecessor, o FlexUnit 0.9, como os metadados de teste ([Test], [After] e [Before], para citar as mais populares), Theories, DataPoints e Assumptions que são úteis para testar grandes quantidades (talvez até infinita) de dados e ver como a aplicação se comporta e a possibilidade de executar os testes com diferentes Runners.
Este tutorial tem como objetivo mostrar o básico de testes unitários no Flex, sem se aprofundar muito nos recursos avançados do framework de testes. Eu pretendo ir postando mais tutoriais à medida que eu for me aprofundando na tecnologia.
O setup
Para usar o FlexUnit4, você precisa baixa-lo aqui. Após isso, crie um projeto no Flex Builder e adicione todas as libs que vieram no pacote no seu diretório libs:

Como o bom e velho TDD manda, vamos primeiro escrever a classe de teste de exemplo antes de escrever nosso código de produção.
A classe de teste
Uma classe de testes é uma classe comum que usa a classe Assert para fazer asserções. No exemplo que irei mostrar, usarei dois tipos básicos de asserção, mas se você observar, o FlexUnit possui vários tipos diferentes de asserções:
package tests
{
import org.flexunit.Assert;
import org.flexunit.runner.manipulation.filters.IncludeAllFilter;
import production.BasicClass;
public class BasicTests
{
public function BasicTests(){}
private var basicClass:BasicClass;
[Before]
public function before():void
{
basicClass = new BasicClass();
}
[Test]
public function Verifica_Se_As_Duas_Strings_Sao_Iguais():void
{
var str:String = "MinhaString";
Assert.assertTrue(basicClass.areStringsEqual(str,"MinhaString"));
}
[Test]
public function Verifica_Se_A_Soma_Retorna_Resultado_Correto():void
{
var soma:int = 10;
Assert.assertEquals(soma,basicClass.somar(2,8));
}
[After]
public function after():void
{
//codigo de after
}
}
}
A suíte de teste
A suíte de testes inclui nosso caso de teste descrito acima e será útil para o Flex executar nossos testes. Sendo assim, nossa suíte de testes ficaria mais ou menos desse jeito:
package tests
{
[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class MyTestSuite
{
public var baseTest:BasicTests;
public function MyTestSuite(){}
}
}
UITestRunner e o FlexUnitCore
O UITestRunner é um componente do FlexUnit que mostra os testes numa interface gráfica. Ele ficará na nossa aplicação e mostrará os resultados dos testes.
O FlexUnitCore será o responsável por carregar as suítes de teste e por passar os dados de saída de testes para o UITestRunner. No nosso caso, nossa aplicação principal ficaria assim:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="run()" layout="absolute" xmlns:flexUnitUIRunner="http://www.adobe.com/2009/flexUnitUIRunner">
<mx:Script>
<![CDATA[
import tests.MyTestSuite;
import org.flexunit.listeners.UIListener;
import org.flexunit.runner.FlexUnitCore;
public var core:FlexUnitCore;
public function run():void
{
core = new FlexUnitCore();
core.addListener(new UIListener(uiRunner));
core.run(MyTestSuite);
}
]]>
</mx:Script>
<flexUnitUIRunner:TestRunnerBase id="uiRunner" width="100%" height="100%"/>
</mx:Application>
O código de produção
Ufa! Depois de escrever a classe de teste, a suíte de teste e o runner, podemos nos focar em fazer nosso código de produção
. Dêem uma olhada em como ficaria o dito:
package production
{
public class BasicClass
{
public function BasicClass(){}
public function areStringsEqual(string1:String,string2:String):Boolean
{
return (string1==string2);
}
public function somar(valor1:int,valor2:int):int
{
return valor1+valor2;
}
}
}
E Voilà!
Depois de tudo pronto, a cara da criança ficaria mais ou menos assim:
Legal, não? E ainda dá pra fazer com que o FlexUnit4 exporte o resultado dos testes para um arquivo XML, permitindo que seus testes no Flex sejam importados pelo seu sistema de Integração Contínua, mas isso é assunto para outro post
Você pode baixar o código fonte aqui e ver os exemplos rodando online aqui.
Good testing!
DojoMoc #5 – O mais emocionante de todos
Hoje nos reunimos na Unimontes para realização de mais um Coding Dojo. No total foram quatro pessoas:
- Diego Caxito
- Elvis (não, ele não morreu
- Diego Guimarães
- eu
A linguagem escolhida foi o JavaScript (\o/) e usamos o QUnit como suíte de testes. Apesar de todo o esforço do setup inicial do nosso caso de teste, o pessoal gostou bastante de fazer testes usando o QUnit.
O problema
Resolvemos escolher o problema na hora (inclusive, esse foi um dos motivos pelos quais nos atrasamos). O problema escolhido foi o A Diversion, um problema simples aparentemente, mas que nos deu um pouco de trabalho, principalmente na hora de explicar.
Os testes rodaram bem no Chrome 4 e no Internet Explorer 8. Como rodou no IE8, dá até pra considerar o código à prova de balas
Os testes possuem uma versão online disponível aqui. Pra quem quiser baixar, o link é esse.
A emoção
Tivemos que quebrar o problema principal em 3 problemas de menor tamanho para conseguirmos resolver. A última parte consistia em fazer um conversor decimal-binário na mão! Eu até tentei sugerir pra que pegássemos um pronto na net e focássemos mais na resolução do problema, mas a galera quis ser matuta. E foi bom assim, pois deixou o problema muito mais divertido.
Além do mais, é a primeira vez que trabalhamos com uma linguagem dinâmica no DojoMoc. Espero que se torne preferência da galera trabalhar com linguagens dinâmicas, pois, na minha opinião, facilita o trabalho.
Uma coisa que deu mais emoção ainda foi ter feito tudo usando o Notepad++ sem o langs.xml estar funcionando direito. Foi a primeira vez que não usamos uma IDE
E pra completar: dos 5 Dojos que fizemos até hoje, nós só conseguimos resolver o problema em duas vezes. O de hoje foi uma dessas vezes. Parabéns pra galera!
Não vai dar pra postar a nossa retrospectiva aqui agora porque os post-its ficaram com o Diego Caxito, mas em breve estaremos disponibilizando mais informações sobre o nosso Dojo de hoje no blog oficial.
É isso aí pessoal, até a próxima!



