Meu Quadro de Medalhas: Aprendendo Ruby

O Soro escreveu há um tempo atras sobre como conseguir motivação pra aprender algo novo, como uma linguagem de programação. Desde a primeira vez em que ouvi falar de Ruby, la em 2001, eu estou tentando achar algum jeito de aprender a linguagem, mas a procrastinação sempre fala mais alto. Acho que o único jeito que encontrei pra aprender uma nova linguagem é ter um projeto, alguma coisa prática de verdade, nem que seja algo meio sem sentido mesmo, só pra ter um objetivo concreto e ir aprendendo com as necessidades que vão surgindo. Como não tava tão inspirado pra criar um novo job4dev (que foi o “projetinho” do miguel), e estamos em tempos de Olimpíadas, eu resolvi aprender um pouco de Ruby escrevendo um programa pra gerar meus próprios quadros de medalhas.

Eu sempre tive uma certa ressalva com esses quadros de medalhas olímpicos. Em geral eles colocam medalhas de ouro acima das de prata, e essas acima das de bronze. Isso faz com que um país que tenha uma mísera medalha de ouro fique na frente de um outro que tenha 10 de prata, o que eu acho meio que injusto. É claro que agora com os EUA perdendo da China nos ouros, a TV americana tá colocando o ranking baseado no total de medalhas. Mas daí você tá dizendo que uma medalha de prata vale o mesmo que uma de ouro, o que não é a verdade. Uma solução seria colocar pesos pra cada tipo de medalha.

Outra coisa meio injusta é que na China tem muito mais gente que na Austrália, então um ranking baseado em população também seria interessante. E mais ainda, um atleta como o Michal Phelps consegue 8 medalhas numa olimpíada, mas um time completo de futebol consegue no máximo 1. Porque não multiplicar o valor da medalha pelo numero de atletas na equipe (titular, pelo menos)?

Então a idéia inicial que eu tive foi a seguinte. Estamos em plena Web2.0, então eu devo conseguir alguns serviços que provenham os dados necessários e eu faco uma espécie de mash-up, calculando meus rankings. Eu precisaria de 2 serviços, um com os dados sobre as medalhas e esportes, e outro com dados sobre as populações dos países.

Infelizmente logo na minha primeira tarefa eu já encontrei problemas. Informação é dinheiro, e foi impossível encontrar algum site na Web que disponibilizasse as informações sobre as medalhas. Existem vários sites mostrando tabelas ou disponibilizando RSS com noticias, mas uma API pras medalhas não existe. Acabei descobrindo que existe uma tal de World News Press Association que tem o monopólio das feeds sobre os eventos olímpicos e eu teria que pagar pra conseguir acesso (como o google fez).

A minha solução foi criar um programinha em Ruby que fizesse parser das paginas do UOL. Primeiro eu baixo a pagina do quadro geral de medalhas, daí eu recursivamente baixo as paginas de cada pais (que tem no combo box). Não é exatamente uma solução elegante, mas graças as boas tags no fonte da UOL e ao HPricot (uma biblioteca pra fazer parse de HTML) não foi tao difícil agregar os dados e gerar um CSV. Porem, surgiram dois problemas. Primeiro que eu tive que abandonar minha idéia de multiplicar as medalhas pelo numero de atletas no esporte, pois essa informação seria muito chata de conseguir. Depois que eu tive que criar uma tabela traduzindo os nomes dos países de português pra inglês, já que eu queria apresentar as tabelas em inglês, e os dados de população também estariam em inglês.

O segundo passo seria conseguir informações sobre população. Eu achei um tal de Population Reference Bureau com as informações necessárias, só que de novo esbarrei em problemas. Primeiro que eles não tem um RSS ou um web service, então eu tive que fazer copy e paste da tabela. E segundo que algumas informações relativas aos países são diferentes da pagina da UOL, ou tem que ser agregadas (por exemplo, tive que adicionar a população de varias colonias francesas na da França). Pra alguns países estranhos (como “Ilhas Virgens Americanas”), que não tinham informação no Bureau, eu tive que pegar no wikipedia mesmo.

Finalmente, com todos os dados em arquivos, eu pude criar um outro programinha em Ruby pra analisar os dados e gerar meus rankings. Eh claro que como isso é just for fun, a interface deixa muito a desejar. Mas pra quem tiver interesse, alguns rankings que eu gerei estão nesse diretório. Eu atualizo os dados usando o parser uma vez por dia. Os cabeçalhos dos rankings descrevem o que foi usado pra gerar os”values” pras medalhas (counters) e pro valor total (aggregators) a partir do numero de medalhas, e por quais campos ordenar os países.

Bom, lições aprendidas:

  • realmente o melhor jeito pra aprender uma linguagem de programação é usando. Eu não posso dizer que agora sou um programador Ruby, mas aprendi um monte de detalhes e foi bem melhor do que qualquer tutorial.
  • apesar de existir muita informação pela web, o mais chato (e difícil) é conseguir agregar a informação de varias fontes que em geral são “um pouquinho diferentes”. Por exemplo, não teria como automatizar o matching dos nomes dos países em diferentes línguas, nem como programar a intuição de “somar as populações das colonias”, a não ser que você tenha muito mais meta-informação, ou recorra a heurísticas.
  • a China nem é tao boa assim se a gente considerar o tamanho da população ;-)
  • o Brasil continua ruim, em qualquer ranking mais ou menos razoável que se faça.

O proximo passo seria aprender Ruby on Rails e fazer uma interface em que os usuarios pudessem escolher como fazer os rankings. Mas como eu teria que instalar outro servidor web e um banco de dados, e eu to meio sem tempo, vai ter que ficar pra depois… e se interessar a alguem eu mando os dados.

Mais brincadeiras com bits

Há algum tempo atrás, escrevi aqui algumas curiosidades sobre Ponto Flutuante, bits afins. Semana passada, tive que corrigir alguns pequenos bugs no meu código de leitura de buffers de bytes, e descobri outra curiosidade com operação de bits em Java. Resolvi compartilhar com vocês, apesar de saber que a grande maioria dos programadores hoje em dia considera este tipo de conhecimento inútil, já que raramente se trabalha diretamente com bits. Verdade, raramente. Mas se aconteceu comigo, pode acontecer com qualquer um. E conhecimento nunca é demais.

Vamos lá!

Em Java, todo tipo primitivo de dados (byte, short, int, long, float e double) é sinalizado, o que significa que seus valores podem ser positivos ou negativos. Um byte pode ter valor de -128 a 127, um short varia de -32768 a 32767, e assim por diante.

Já em C, tipos primitivos podem ser sinalizados ou não sinalizados. Um byte sinalizado em C pode assumir os mesmos valores que um byte em Java, mas um byte não sinalizado pode assumir valores entre 0 e 255.

Assim sendo, quando se escreve um programa em Java que deve ler dados gerados por um programa em C, é importante saber se estes dados são sinalizados ou não. O mais divertido disso tudo é que não existe forma de saber isso apenas analizando os dados, porque eles são idênticos: um byte sinalizado continua tendo 8bits e podendo armazenar 255 valores.

Neste ponto me parece interessante explicar como um número negativo é armazenado em um tipo básico. Primeiro conceito: em tipos sinalizados, o bit mais a esquerda indica o sinal: 0 positivo, 1 negativo. Mas para se obter o inverso de um número, não basta apenas mexer no bit mais a esquerda. É necessário usar um segundo conceito: complemento de 2! Para se obter o complemento de 2 de um número, basta inverter os bits e somar 1. Por exemplo, se N = 7 = 00000111, o seu complemento de 2 será 11111000+1 = 11111001. Para se obter a representação binária de um número negativo, basta gerar o complemento de 2 da representação binária do seu valor positivo! Assim sendo, -7 em binário é representado por 11111001.

Este mecanismo foi criado para facilitar as operações aritméticas nos processadores, pois elimina a necessidade de um circuito específico para subtração: o processador precisa calcular apenas o complemento de 2 do subtraendo, e efetuar a soma. Por exemplo

7 - 2 = 0111 - 0010 = 0111 + 1110 = 0101 .

Muito bem, voltemos portanto ao problema original…

Quando passamos um valor sinalizado de C para Java, não há problemas. Se eu leio um byte gerado pelo programa em C em um byte em Java, ou em um short (16 bits), ou em um int (32 bits), ou em um long (64 bits), o resultado será exatamente o esperado. Agora, se queremos ler um valor não sinalizado gerado por um código em C em um programa Java, é necessário escrever os bits em um tipo primitivo de tamanho maior.

Para escrever bits em um tipo primitivo, existem dois mecanismos: ou fazemos um AND binário com o endereço de destino contendo somente bits com valor 1, ou fazemos um OR binário com o endereço de destino contendo apenas bits com valor 0.

00000000 | 0110 = 00000110
11111111111 & 0110 =11110110

Por exemplo, supondo byte 11111001. Já vimos anteriormente que esta sequência de bits corresponde ao valor -7, mas também correspondeao valor 249 em um byte não sinalizado. Se quisermos obter o valor 249 em Java, teremos que gerar uma variável igual ou maior que um short.

E agora vem a curiosidade que motivou este texto (sim, todo o resto era apenas preparação, espero que tenha sido proveitoso) .

Pelo o que eu disse acima, para gerar o short com o valor 249, ambos os códigos abaixo seriam equivalentes:

short s1 = 0×0000 | 0xF9

ou

short s2 = 0×00FF & 0xF9

correto?

Errado!

Se eu mandar imprimir s2, o resultado será 249, mas se eu mandar imprimir s1, verei que o resultado será -7. Porque???

Simples: antes de efetuar uma operação binária, a JVM efetua um casting implícito de todas as variáveis para int. Como Java não entende tipo não sinalizado, ele faz casting do nosso byte levando em conta o valor -7, que em um int de 32 bits fica sendo 0xFFFFFFF9. O short 0×0000 passa a ser 0×00000000, e o short 0×00FF passa a ser 0×000000FF. Assim sendo, as operações descritas acima na verdade são:

short s1 = 0×00000000 | 0xFFFFFFF9 = 0xFFFFFFF9 = -7

e

short s2 = 0×000000FF & 0xFFFFFFF9 = 0×000000F9 = 249

——————————————————-

Adendo do autor:

Para aqueles que tenham dificuldades de entender notação hexadecimal, e como converter isso para binário e vice-ver, eis uma dica:  um símbolo em hexa pode assumir 16 valores (0,1,2,3,4,5,6,7,8,9,A,B,C,D,F,). Sendo assim, cada símbolo em hexa corresponde exatamente ao valor de 4 bits, e portanto são necessários dois símbolos em hexadecimal para descrever um byte.

Tabus e baixarias

Nas últimas semanas tenho trabalhado em um projeto de integração entre um sistema em C e um sistema em Java: o sistema original, legado, é completamente em C, e a equipe na qual eu trabalho está reescrevendo algumas partes em Java, e eu tenho que fazer o sistema antigo conversar com o novo. O sistema em C utiliza um sistema de comunicação interna que consiste basicamente em serializar bytes e mandar via UDP. Isso torna o processo bem rápido e eficiente, mas torna a comunicação entre plataformas bem complicada, por causa de problemas como alinhamento de bytes, padding, little endian, big endian, ponto flutuante, e por aí vai.

Por isso tive que rever vários conceitos, além de relembrar várias coisas em C. Não trabalhava com C desde 2002, quando participei do projeto AURORA, organizado pelo CenPRA. O objetivo do Aurora era de construir um dirigível capaz de voar sozinho, usando dados de sensores, GPS e de câmeras de vídeo. Minha missão dentro do projeto foi de desenvolver a infraestrutura para captação de imagens através de barramento IEEE 1394 (firewire), processamento e extração de certos parâmetros em tempo real e envio de alguns frames para uma estação de controle em terra. Foi C na veia, e ainda tive que estudar IEEE1394, drivers para linux, formatos de vídeo, processamento de imagens, envio de pacotes via UDP, e muitos outros conceitos básicos. Me diverti muito nesta época.

Voltando ao projeto atual, uma das tarefas necessárias era de receber um fluxo de bytes e extrair informações seguindo um descritor da mensagem. Como meus campos de informação dentro do fluxo de bytes tinham posições e tamanhos pouco convencionais (12 bits, 3 bits começando no bit 4 do byte 2, e por aí vai), não consegui encontrar nenhuma lib que resolvesse meu problema de forma adequada (em particular, nenhuma lib de extração de dados trabalha corretamente com campos de bits). Por isso resolvi extrair os bits na mão, escrevendo algumas operações binárias: o resultado final ficou bastante bom e conciso. Mas várias pessoas me perguntaram porque eu fiz a loucura de implementar isso na mão. Segundo eles, deveria ter pesquisado mais, porque provavelmente algum engenheiro da Sun havia feito algo melhor e mais robusto.

Concordo que seja possível que eu não tenha procurado o suficiente. Mas escrever algumas poucas linhas de operações binárias não me parece ser tarefa do outro mundo. Talvez eu seja arrogante o suficiente para me achar melhor do que os engenheiros da Sun (ou pelo menos tão competente quanto). Mas talvez também os programadores estejam criando tabus em relação a alguns tópicos de computação, chamados por muitos de baixarias.

A evolução na computação se faz por meio de criação de camadas de abstração, que nos permitem trabalhar sem nos preocuparmos com certos problemas. Hoje em dia, quem programa em Java, Python, Ruby e outras linguagens similares não se preocupa mais em gerenciar memória, em perder ponteiros. ORMs permitem que a base de dados seja vista como um conjunto de objetos. RMI e RPC enviam objetos e estruturas de dados de uma máquina para a outra. E acreditem: eu adoro estas abstrações! Adoro trabalhar com dicionários, listas e tuplas em Python, adoro não ter que gerenciar ponteiros em Java. Mas duas ressalvas precisam ser feitas.

A primeira já foi feita pelo Joel, no artigo The Law of Leaky Abstractions: estas abstrações são ótimas, mas não são perfeitas e muitas vezes falham. E quando falham, é preciso conhecer os fundamentos daquilo que está por baixo. Quando sistemas de ORM retornam resultados esdrúxulos, é preciso entender que o sistema subjacente não trabalha com objetos, mas com tabelas. Quando struts não da conta de tratar uma requisição, é preciso entender que no fundo no fundo, um form é uma string de requisição HTTP. Pode parecer bobo, mas é incrível perceber a quantidade de programadores que simplesmente não entendem o que se passa por debaixo do pano. Tudo é mágico.

A segunda ressalva é o ponto que eu quero ressaltar neste texto: estas camadas de abstração criam tabus. Hoje as pessoas tem receio de escovar bits, ou processar um UDP na mão. Muito em breve, SQL será algo de outro mundo, uma vez que Hibernate, RoR e Django permitem que objetos sejam criados de forma direta. HTTP e CGI já são conceitos do passado: hoje temos forms, event handlers e componentes. Para tudo, se busca um framework, uma lib. Para tudo, se acha que o que é feito pelos engenheiros da Sun é melhor. Eu tive esta nítida impressão conversando com um colega de trabalho que já tem muiiiiitos anos de estrada. Ele tem uma boa experiência em programação de microcontroladores, e ele é da época em que C era novidade no mercado. E segundo ele, mexer com bits era algo trivial e corriqueiro naquela época.

Que fique bem claro: eu adoro não ter que mexer nestas coisas. Mas sei que problemas deste tipo podem aparecer na nossa frente de vez em quando, e quando aparecerem nós temos que poder resolve-los. E para isso, não podemos ter medo de passar por cima das abstrações. Por isso, eu defendo que todo programador deveria mexer em algum projetinho em C de tempos em tempos (um ou dois meses a cada 5 anos por exemplo). Isso já seria suficiente para lembrar que o mundo computacional não é tão alto nível quando gostaríamos. E o prazer de voltar para nossas caixas pretas é incomensurável.

ClockingIT

Existe uma ferramenta muito legal para controle de projetos, bugs, releases e afins disponível na web: ClockingIT.

Este projeto tem uma história bem peculiar: foi desenvolvido por um casal norueguês, Erlend e Ellen Simonsen. Erlend é desenvolvedor e é responsável por toda a parte de programação. Ellen é designer e cuida de toda a parte visual.

O ClockingIT segue a mesma receita de muitos projetos de alta qualidade e valor agregado disponíveis por aí: nasceu de uma necessidade do próprio desenvolvedor. Erlend é um consultor de tecnologia independente e desenvolve projetos sob medida para vários clientes, e sentia a necessidade de ter uma boa ferramenta de gerenciamento de projetos. Seguindo a filosofia do Getting Real, resolveu por a mão na massa e começou a desenvolver o ClockingIT usando a plataforma Ruby On Rails.

O sistema permite o cadastro de diversos projetos e colaboradores. Em cada projeto, é possível criar milestones e tarefas (com diversos graus de prioridade, nível de dificuldade, tempo estimado de execução e data de entrega) e designar um colaborador para sua execução. Além disso, o sistema permite a criação de subtarefas e permite registrar o tempo levado para executar cada tarefa, gerando um log de trabalho. Com estes dados, é possível criar relatórios diversos, como timesheets que são extremamente úteis para consultores que ganham por hora. E o sistema ainda oferece vários modos de visualização de todos estes dados: timeline, schedule, lista de tarefas…

Mas o grande diferencial, aquilo que me faz ter vontade de escrever sobre o ClockingIT neste blog, é a qualidade da interface. O design gráfico é simples, limpo e extremamente intuitivo. E o site faz um uso intensivo e inteligente de scripts e recursos assíncronos. Eu destaquei a palavra inteligente porque hoje em dia vemos muitos sites usando Ajax simplesmente por usar, apenas para baterem no peito e gritar “Eu sou uebi doispontuzeru!!!”. Olhando a interface do Clocking IT, talvez muitos resolvem repensas suas visões. A interação como o site é extremamente ágil e leve, exatamente como em software desktop. Qualquer ação efetuada por algum usuário é imediatamente refletida na tela de outros usuários conectados no mesmo projeto. É possível saber em tempo real quem está conectado no sistema, o que está fazendo, a quanto tempo está fazendo. E graças ao chat embutido, é possível até conversar com outros colaboradores.

Last, but not least, o sistema oferece integração com iCal (pode ser integrado com Google Calendar ou com o calendário da Apple por exemplo), sistema de RSS, um wiki, fórum , e uma speedbar (uma janelinha pequena) que permite que o usuário marque o início e fim de uma tarefa (com botões de start, stop e pause e um cronômetro rodando em tempo real).

É, definitivamente o ClockingIT não deixa nada a desejar de ferramentas tradicionais de gerenciamento de projetos. E com certeza ele é uebidoispontuzero.

Livro oficial do SVN em Português

Existe no Google Code o projeto svnbook-pt-br para a tradução do livro oficial do SVN, Version Control with Subversion (http://svnbook.red-bean.com/). Existem versões parciais disponíveis para download e o projeto aceita colaboradores.

Proposta de discussão: Sobre Frameworks

Isso não pretende ser um post. Na verdade será uma pergunta aberta à comunidade leitora deste blog.

Frameworks já deram muito o que falar por aqui. Basta dar uma olhada no artigo Sobre Frameworks… escrito pelo Raphael há algum tempo atrás. Eu, ao contrário de muitos de meus colegas, não tenho opinião fechada sobre este tema. Existem frameworks que eu odeio (Hibernate), outros que eu não vejo maiores problemas no uso apesar das críticas (Struts) e alguns poucos que eu gosto muito (no momento, Django).

Fato é que frameworks, por princípio, oferecem um quadro de trabalho dentro da qual temos que nos acomodar. Estava assistindo agora a uma palestra interna da empresa sobre este tema, e o palestrante levantou uma vantagem e uma desvantagem no uso de frameworks que me chamaram a atenção.

A vantagem apresentada foi que frameworks ajudam a desenvolver 80% do trabalho repetitivo de uma aplicação (CRUD por exemplo). Basicamente, eliminando a repetição. A desvantagem é que ele engessa um pouco a criatividade e pode tornar difícil os 20% não previstos nos casos comuns. Alguém na sala acrescentou que o problema é que em muitos casos, para resolver os casos não previstos temos que contornar o framework.

Eu concordo com estes dois pontos. As porcentagens não são nenhum pouco científicas, mas pela minha pouca experiência eu diria que elas são bem aceitáveis. E pareceu ser consenso na sala de que estes 80% justificam a existência do framework. De certa forma eu também concordo com isso.

A minha pergunta, provocativa, é a seguinte: supondo que os 80% que o framework resolve são os problemas genéricos que todos os projetos têm, não seriam os 20% restantes (que frameworks tornam difícil) o que realmente agrega valor e diferencia o produto? Ou seja: no final das contas, os frameworks não atrapalhariam o desenvolvimento daquilo que é a razão de um sistema existir?

Beleza booleana

Até há muito pouco tempo atrás, expressões booleanas para mim eram apenas uma questão de verdadeiro ou falso, ifs, whiles e do..whiles. Nesta época, eu ria quando encontrava trechos de códigosdo estilo

boolean b = true; if (b == true){...}.

A vida era simples, linda e limitada.

Daí eu comecei a brincar seriamente com javascript e python, e descobri que existe muito mais coisas entre o céu e as funções booleanas do que poderia sonhar minha vã filosofia. Neste mundo novo, expressões booleanas podem ser muito mais do que apenas true ou false: elas podem ser formas extremamente elegantes e compactas para atribuição de valores.

Vamos por partes. Em Java, apenas variáveis do tipo booleanas ou expressões que retornem variáveis do tipo booleanas (maior que, menor que, igual a, contém, …) podem ser utilizadas em expressões booleanas. Uma construção do tipo if(1) não funciona.

Em linguagens de script, qualquer objeto pode ser avaliado como uma expressão booleana. Em Python por exemplo, a seguinte regra é aplicada: valores False (booleano), 0, “”, e None (valor nulo) são avaliados como falso; qualquer outro valor é avaliado como verdadeiro. A expressão (1 and 2) seria avaliada como true por exemplo.

Um outro ponto interessante em Python e Javascript é que expressões booleanas não retornam simplesmente True ou False: elas retornam o valor de um dos objetos da expressão. Uma expressão com AND retorna o último valor da expressão caso todos elementos sejam avaliados como verdadeiros, ou retorna o primeiro valor que fez com que toda a expressão fosse avaliada como falsa. Por exemplo: 1 and "miguel" and 2 retorna 2, porque todos os elementos da expressão são verdadeiros, e portanto a expressão toda é verdadeira. Já 1 and 0 and 2 retorna 0, uma vez que este é o primeiro elemento avaliado como false. E como todos sabemos, se um elemento é falso, a expressão toda é falsa.

No caso de uma expressão OR, ela retorna o primeiro elemento que for avaliado como verdadeiro, ou o último elemento da expressão caso todos os anteriores sejam avaliados como falsos. Por exemplo (1 or 2) retorna 1, e (0 or "") retorna “”.

Ótimo. Então como podemos usar isso para escrever expressões compactas, úteis e elegantes? Eis algumas sugestões:

  • Valor default para uma variável: OR pode ser usado para garantir que caso um parâmetro seja passado com valor nulo para uma função por exemplo, ele receba um valor default:
    var v = param || “default”
  • Expressões ternárias: o uso de OR e AND pode criar uma função ternária em linguagens que não possuem esta construção (Python por exempl0):
    var v = (condicao AND valor1) OR valor 2

Aproveito pra levantar um ponto: estilo compacto é algo bom ou ruim? Um argumento muito utilizado contra expressões compactas como as descritas acima é que prejudica a legibilidade. De fato, pode ser mais difícil de ler à primeira vista. Mas mesmo construções mais verborrágicas podem ser dificeis de serem lidas: tudo depende de quão treinado é o olho e o cérebro do leitor. Portanto, eu acho que é apenas uma questão de estar acostumado a ler código de qualidade.

Preview no Job4Dev

Mais uma singela porém importante novidade no Job4Dev: agora o sistema mostra um preview do anúncio para que o usuário possa validar o texto e a formatação produzida pelo markdown antes de confirmar a submissão.

Dica: Ajax, JSON e IE 6

Esta dica é bem pontual, e talvez resolva a vida de no máximo duas pessoas. Mas o problema aqui abordado me custou minutos preciosos, e portanto vou aproveitar o fato de ter um blog para compartilha-lo com vocês. Sem contar que faz um bom tempo que eu não escrevo nada mais técnico.

Cenário básico: aplicação web com interface contendo vários trechos que necessitam de comunicação assíncrona com o servidor (a.k.a Ajax). Por motivos de projeto, a resposta vem em formato JSON (para resumir, eu tive que substituir DWR por Prototype, e para ser o menos intrusivo possível na aplicação, usei o mesmo formato de transmissão de dados do framework).

Dentre os vários dados recebidos do servidor, um deles é uma estrutura de dados representando um endereço:

{cidade: {id: 1, nome: "Sampa"}, estado: {id: 1, nome: "SP"}, pais: {id: 1, nome: "Brasil"},}

Muito bem. Para transformar este trecho em um objeto tratável pelo javascript como uma estrutura de dados, eu usei o comando var data = eval("("+response.responseText+")"), onde response é o objeto de resposta da requisição.

No Firefox, o sistema funcionou maravilhosamente bem. No IE 6, pra variar, necas. Não testei no IE 7.

O problema foi a última vírgula antes da última chave. O uso de chaves indica que estou descrevendo um dicionário (contendo pares chave: valor). Ao colocar uma vírgula no final, o IE entende que teremos mais um par à frente, e reclama ao encontrar uma chave. Tirei a virgula, e tudo funcionou perfeitamente.

________________________________________

Adendo feito algumas horas depois: justiça seja feita, o IE segue a especificação formal do JSON ao pé da letra. Vendo o diagrama da sintaxe do JSON no site json.org, vi que após uma virgula deve haver um par chave:valor. MEA CULPA.

Testando aplicações web com Selenium

Por Odracir Antunes Júnior

Creio que boa parte dos desenvolvedores sabe da importância dos testes automatizados como ferramenta indispensável no desenvolvimento de software. Mesmo assim, para deixar as coisas ainda mais claras, gostaria de compartilhar uma experiência que tive com meus amigos em um projeto recente.

Estavamos trabalhando em um projeto de produto genérico, que serviria para várias empresas. Conseguimos um primeiro cliente que, obviamente, solicitou várias adequações para que o produto pudesse se utilizado por ele. Algum tempo depois tínhamos mais dois clientes além daquele inicial. Um deles pretendia utilizar apenas um sub-conjunto do produto original, e outro precisava de mudanças que eram incompatíveis com os outros dois.

A gestão da configuração do projeto se tornava cada vez mais complexa. Precisávamos atuar em frentes diferentes, para atender às necessidades dos clientes. Tínhamos que implementar as novas funcionalidades, porém sem quebrar o que já existia. Pra variar, acabamos atrasando. E os novos prazos estavam ficando cada vez mais apertados. Algumas vezes nós chegamos à entregar versões preliminares para homologação, com bugs em funcionalidades que já tinham sido testadas e aprovadas em versões anteriores. Isto nos causava um grande desgaste perante o cliente, e era preciso garantir a qualidade do que estava sendo entregue.

Tínhamos uma equipe de testes que também estava sobrecarregada, pois quanto mais complexos se tornavam os produtos, maiores eram as dificuldades na simulação dos cenários diferentes para os testes. Foi definido um “Smoke Test“, com as funcionalidades essenciais do produto que eram comuns entre os clientes. No meio da correria, depois de um refactoring crítico na infraestrutura do projeto, eu tive que testar manualmente a aplicação. Fiquei 4 dias testando e mal passei de 40% da cobertura básica!

Passada aquela correria, começamos a automatizar o processo de “Smoke Test” tanto quanto possível. Já sabíamos que muitas outras correria ainda nos esperavem num futuro não muito distante!

Boa parte das aplicações desenvolvidas últimamente são aplicações WEB, e portanto também é fundamental poder fazer testes através do browser, como se fosse um usuário comum operando o sistema. Obviamente isto não exime o desenvolvedor de implementar os testes unitários. Os testes através da camada web devem ser um complemento aos testes mais básicos.

O Selenium é uma ferramenta de para testes de aplicações WEB, distribuído sob a “Apache License, Version 2.0“. Temos os seguintes produtos, e modos de uso do Selenium.

 

Selenium Core - (Modo direto)

Os testes são efetuados diretamente através do browser. As páginas de teste devem estar hospedadas no mesmo servidor que o programa/site a ser testado. Esta restrição/característica é função da segurança relativa à mesma origem requerida pelo javascript.

Vantagens:

  • Suporte para todos os browsers

Desvantagens:

  • É necessário a instalação remota no servidor.
  • Possui algumas limitações para testes mais complexos.
  • Pode ter um comportamento irregular quando se testam páginas com ajax, onde é necessário um controle maior do tempo, e/ou seqüencia de eventos. Este comportamento é altamente dependente do “engine” java script do browser. Dependendo do caso, às vezes pode apresentar falsos erros em função da priorização das atividades, já que tando “quem testa” quanto “quem é testado” estão sendo executados sob o mesmo “engine” java script, e comportamentos concorrentes podem não ser tão previsíveis assim …

Selenium IDE - (Modo indireto - Plugin no browser)

Os testes são efetuados através de um plugin instalado no FireFox. Este plugin é um ambiente integrado de desenvolvimento. Permite gravar a navegação do usuário, e depois repeti-la à titulo de teste. Também permite exportar os testes gravados em outros formatos. (Maiores explicações adiante…)

Vantagens:

  • A instalação é local e simples.
  • É muito fácil de usar.
  • Permite gravar sessões de teste para uso posterior.
  • Permite exportar as sessões de teste como arquivos fonte Java, C#, Perl, PHP, Python e Ruby, que podem ser usados pelo Selenium RC.
  • Excelente para quem inicia o uso do Selenium.
  • Não é preciso saber programar.

Desvantagens:

  • Funciona como plugin apenas no FireFox.
  • Possui algumas limitações para testes mais complexos.
  • Pode apresentar o mesmo comportamento irregular relatado no item Selenuim Core. (colocar link local para #L1)

Selenium RC - (Modo indireto - Programa de teste + Proxy)

Os testes são efetuados através de um programa, que comanda o browser através de um proxy. Este programa pode ser escrito em Java, C#, Perl, PHP, Python e Ruby.

Vantagens:

  • Permite o uso de verdadeiras linguagens de programação.
  • Permite um controle muito mais apurado do tempo, seqüencia de eventos, etc. …
  • É possível importar os testes gerados pelo Selenium IDE.
  • Muito mais flexível e poderoso. Pode evoluir até para grandes suítes de testes, integração contínua, geração de relatórios . Como o programa está nas suas mãos você pode fazer o que quiser!

Desvantagens:

  • A instalação e configuração do ambiente é um pouco mais trabalhosa.
  • É necessário saber programar.
  • Pode ser mais complicado escrever os testes à partir do “zero”.

Qual ferramenta/modo eu devo usar ?

Além das informações listadas aqui, gostaríamos de sugerir a seguinte abordagem híbrida:

  • Instale o Selenium IDE e crie os seus testes básicos.
  • Exporte esses testes como programas (java, por exemplo).
  • Crie um projeto com as suítes de teste para uso com o jUnit.
  • Faça um refactoring nas classes geradas pelo Selenium IDE, pois o código gerado tem muita redundância.
  • Melhor ainda seria arrumar o código para ficar simples como uma mini “DSL” (Links #9 e #10), mais adequada para a sua aplicação, com chamadas de mais alto nível.

Depois de que automatizamos uma parte dos testes, aquilo que eu levei 4 dias era feito em apenas 20 minutos! Uma cobertura mais abrangente e confiável! A tranquilidade e a segurança que temos depois que os testes passam após um “refactoring”, ou mesmo antes de uma entrega do sistema para o cliente, é algo que não tem preço!

Moral da história: O tempo utilizado na elaboração de testes automatizados não é um tempo “gasto”. Na verdade é um tempo “investido”!

[Odracir Antunes Júnior é Analista de Sistemas com mais de 20 anos de experiência de desenvolvimento de sistemas em C, C++ e Java]

Especial de Natal Log4Dev: construindo um site de notícias usando Python - Parte 2

Vamos dar uma olhada nos nossos requisitos, e apresentar algumas questões de tecnologia:

  • O site tem que ser capaz de autenticar e identificar unicamente cada usuário que deseja cadastrar links.
  • Deve ser capaz de manter uma lista de quem foi o primeiro a enviar um link, além da data que o link foi enviado.
  • Deve ter um sistema que permita ao usuário indicar se gostou (aprovou) ou não gostou (rejeitou) um link enviado por qualquer pessoa que utilize o serviço.
  • Deve permitir que cada link enviado possua um fórum de discussão.
  • Deve permitir que uma pessoa possa iniciar um tópico de discussão, sem enviar um link. No caso, vamos fazer o seguinte: se o usuário preencher apenas os campos de título e comentário em um formulário de link, mas deixar o campo para a URL em branco, vamos criar um link para um item dentro do próprio site.
  • Deve permitir ao usuário enviar um lote de links a partir de uma fonte que ele já conheça. Isso vai servir para que o sistema, no futuro, tenha uma grande base de links prévios para aprender rapidamente.
  • Deve permitir que o usuário faça o seu voto (aprovado/rejeitado) sem sair da página que está. Para isso, vamos usar uma pitada de AJAX.

Tendo os requisitos delineados, podemos ver que vamos precisar dos sistemas comumente usados em aplicativos web: um banco de dados, um servidor web, um sistema para geração de páginas dinamicamente. Além disso, teremos que usar alguma biblioteca para importar links e parsear RSS.

A parte de programação já foi definida no título: vamos usar Python. É o que estou usando ultimamente para meus outros projetos, é uma linguagem elegante, divertida (sim, diversão conta), dinâmica, com bibliotecas fartas e bem documentadas como parte da biblioteca-padrão. Se nada disso serviu como argumento, diga para o seu chefe que você vai aprender Python pois ficou sabendo que o pessoal do Google usa, e tudo que eles usam tem que ser bom, não é mesmo?

Para o servidor de banco de dados: PostgreSQL. Maduro, estável, bastante documentação. Outros bancos de dados serviriam, mas escolhi PostgreSQL por pura comodidade. Se você quiser portar os scripts SQL que eu colocar aqui para seu banco de preferência, creio que não terá dificuldades.

Para a parte de AJAX, vamos favorecer a prata da casa: Juice Lib é uma biblioteca pequena, mas com funcionalidades bem pensadas para a parte de comunicação assíncrona com o servidor. Eu tenho enchido um pouco o saco do Miguel na questão de manipulação de DOM (a juice faz isso através de extensão de métodos sobre string, o que pode vir a te causar dor de cabeça se o seu código Javascript começar a crescer muito), mas o resultado geral é poderoso o suficiente para que possamos ter o esquema de apresentação da votação em pouquíssimas linhas de Javascript.

Resta falar sobre qual sistema vamos usar para formarmos uma “Aplicação Web” propriamente dita. Controle de sessão, classes controllers, formas para acessar o banco de dados, apresentação de páginas construídas dinamicamente, etc, etc, etc.

Eu já disse que odeio frameworks. O que eu quero é algo que pudesse funcionar como um único módulo ou biblioteca, que pudesse ser importado a partir de um shell Python e me oferecer as funcionalidades necessárias para um webapp.

O que vamos usar, então, é um sistema que seja o anti-framework: esse sistema, para mim, é o web.py

O que diferencia o web.py dos outros frameworks para aplicações web desenvolvidas em Python?

Simples: a filosofia.

Muita atividade ocorreu na comunidade de desenvolvedores Python, buscando uma resposta para o sucesso do Ruby On Rails. Começaram então a pensar em implementar um framework que pudesse ser tão “pragmático” e “rápido” quanto o Ruby On Rails.

E isso levou a uma febre de grupos desenvolvendo frameworks para Python. Sistemas que fazem mapeamento OR. Que abstraem sua camada de dados completamente. Que abstraem a camada de apresentação completamente. Que abstraem a camada de controle completamente. Que escrevem elogios na tela enquanto eles fazem tudo automaticamente para você.

O problema: abstrações excessivas falham. Cada um dos grupos dos grandes frameworks (Turbogears, Pylons, Django) tinha o seu próprio dialeto para o desenvolvimento de aplicações web, alguma coisa parecida com Python, mas não exatamente Python.

Faltava uma solução que se propusesse a alavancar os conhecimentos tradicionais que as pessoas acumulam ao trabalhar com sistemas web.

O web.py tem essa filosofia. Por exemplo: ao invés de se preocupar em implementar um módulo que faça mapeamento OR para você, o web.py te dá um módulo que serve para facilitar o acesso ao banco de dados, diretamente e de forma segura. Ao invés de expor objetos em Python para uma camada de apresentação, o web.py facilita o trabalho de construir uma resposta HTTP. Ao invés de impor uma disciplina de trabalho, ele oferece as funcionalidades básicas para que você use seu conhecimento acumulado com outros problemas que você teve que resolver.

(Justiça seja feita: o Django parece ter aprendido parte dessa lição. Muito dos esforços recentes do Django para que ele chegue na versão 1.0 está sendo feito no sentido de retirar o que é chamado de “código mágico”.)

Isso não quer dizer que o web.py é perfeito. Não é. A última versão lançada possui algumas coisas no design que você pode até estranhar, e vou falar deles. Espero para ver se a próxima versão irá corrigir mesmo esses problemas. De qualquer forma, por se tratar de uma biblioteca de recursos auxiliares - ao invés de um framework - a ginástica necessária para contornar esses problemas é muito menor.

Chega de escrivinhar. Amanhã, vamos ao código.

Especial de Natal Log4Dev: construindo um site de notícias usando Python - Parte 1

Introdução

Sem dúvida, esse ano foi um ano interessante para quem participou da WWW. Se em 2006 a revista Time escolhou “Você” como pessoa do ano, nesse ano houve uma consolidação da idéia da “Web Social”.

Estamos só no começo. Estamos só agora descobrindo que a internet, antes do que uma rede de computadores, é uma rede de pessoas. O futuro da internet vai aprender a juntar essas ligações e formas de interação social (o “Grafo Social”) para trazer serviços mais inteligentes e mais adequados a cada um de nós.

Nesse espiríto, e aproveitando o fim de ano - onde todo mundo acaba diminuindo o ritmo de trabalho mesmo - eu pensei em fazer um pequeno passo-a-passo de um “Site Social”, para aqueles que pensam em oferecer um desses serviços.

A idéia

Uma das coisas mais comuns que vimos por aí foi a proliferação de sites onde os usuários mandam as notícias, e a audiência escolhe os textos que são “dignos de capa”, através de “votos” nos links. O maior exemplo para esse tipo de site é o Digg, site com muitos usuários no mundo todo.

Ainda que sites como o Digg até possam trazer eventualmente alguns textos interessantes, já se percebeu que é muito difícil ter um site onde o público seja o único responsável pela determinação do conteúdo relevante. Não por achar que as pessoas não sejam capazes de se gerenciarem, mas pelo fato de ser muito difícil de obter textos e notícias que sejam simultaneamente interessantes e agradem a um grande público.

O Reddit apresentou uma evolução nesse passo. Ele possui um filtro que aprende, através do seu histórico de votação, a te indicar quais links podem ser mais interessante para você.

Mas ainda falta alguma coisa: mesmo o filtro do Reddit não é capaz de me trazer links mais específicos, adequados para os meus interesses. Talvez, se ele puder saber quais os meus gostos, hábitos, idiomas que eu falo, comunidades das quais participo e outras informações gerais, talvez o filtro possa ser mais inteligente e aprender ainda mais.

Bem, eu vou ficar devendo a parte do filtro, por enquanto. Só vou dizer que o nosso site será capaz, quando você acabar, de cadastrar usuários, ver os links enviados, entrar num fórum de discussão para cada link e manter um histórico de votação.

O que eu passei fazendo nos últimos dois dias está aqui. Ao longo dos próximos dias, vou colocar os detalhes e o processo para o desenvolvimento de tal sistema.

Ah, sim. Isso é muito mais um exercício do que algo pra ser considerado software de produção. Trate com carinho. O que mais você queria em dois dias de trabalho?

Getting Real: desenvolvendo o Job4Dev

True artists ship“, artistas de verdade produzem.

Esta frase, atribuida ao Steve Jobs, me foi dita pelo Raphael. Confesso que ela mexeu comigo. Sempre admirei pessoas que desenvolvem seus projetos computacionais, e fazem deles coisas interessantes. Eu estou numa fase de tentar transformar os meus projetos em coisas reais. Se eles estão se tornando coisas interessantes, é outro papo. O primeiro foi este blog, que com muita perserverança está se transformando em um repositório de textos bem interessantes. Depois, coloquei no ar a JuiceLib, que está num processo bem lento de desenvolvimento. Falta tempo e ajuda. E eu trabalho por lotes….

Mas daí, veio a idéia do job board. O interessante neste caso é que este lance do jobboard, antes de ser um projeto de desenvolvimento, era algo que me martelava a cabeça. Me frustrava não encontrar no Brasil um jobboard que me desse prazer de visitar. E depois de um tempo de maturação, cheguei à conclusão de que se ele não existisse, eu teria que criar um. Lembrei de um cara chamado Richard Stallman que não encontrou nenhum editor de textos com os recursos que ele procurava, e daí ele escreveu o Emacs. Citando uma outra referência mais moderna, o livro Getting Real do pessoal da 37 Signals:

A great way to build software is to start out by solving your own problems. You’ll be the target audience and you’ll know what’s important and what’s not. That gives you a great head start on delivering a breakout product.

Muito bem. Eu tinha um problema a resolver. Resolvi atacá-lo de frente. E de quebra, poderia me aprofundar mais em Python. Restava definir o resto do meu ambiente. O editor seria o Emacs, por ser extremamente versátil, ter uma quantidade incrível de ferramentas úteis e poderosas, e ser bem leve. O banco de dados escolhido foi PostgreSQL, por ser um banco free, de ótima qualidade, com portes para Linux, Windows e Mac (ambiente primário de desenvolvimento) e pelo fato de eu ter trabalhado com ele por muito tempo.

O mais difícil foi definir um framework/lib de desenvolvimento web. Comecei avaliando o Turbogears. No início achei interessante, mas por vários motivos não gostei de como ele evoluiu. O Raphael tentou me convencer a me usar o web.py, uma lib bem leve de desenvolvimento web, que eu acabei não escolhendo por achar a doc bem fraquinha. Daí eu descobri o Django, que possuia uma documentação bem completa, um conceito bem legal de oferecer muitos recursos para minimizar a parte CRUD do sistema e um ótimo case de implementação: o site washingtonpost.com.

O desenvolvimento se deu em 3 grandes blocos de trabalho.

O primeiro foi a parte de design de base de dados e entidades, além de primeiros contatos com o ambiente de desenvolvimento. Demorou 3 dias mais ou menos. Boa parte da demora foi pelo fato de eu estar descobrindo o Django ao mesmo tempo que fazia o design da solução. Neste ponto, eu sabia muito bem o que eu queria obter, e sobretudo sabia o que eu NÃO queria! Citando mais uma vez o Getting Real:

Sometimes the best way to know what your app should be is to know what it shouldn’t be. Figure out your app’s enemy and you’ll shine a light on where you need to go.

O segundo bloco de trabalho foi a integração com o design gráfico. E nesta fase aconteceu uma coisa interessante. O Raphael fez um design que se encaixou perfeitamente naquilo que eu tinha em mente. E ao mesmo tempo ele tinha feito uma versão funcional do board em web.py. Rolou então uma competição saudável: roubei o design dele, e durante alguns dias desenvolvemos o mesmo sistema em ambientes diferentes e em paralelo. O que um fazia, o outro corria atrás para fazer melhor. Um impulsionou o outro. Nesta fase, foram feitas as telas principais, o sistema de submissão, e o primeiro RSS. Foram dois ou três dias de trabalho bem intenso, e confesso que fazia muito tempo que não me divertia tanto escrevendo um software. O meu deadline era segunda feira dia 26 de novembro. Neste dia tínhamos um demo rodando.

Foi aí que veio o terceiro bloco de trabalho. Chamamos amigos e conhecidos para serem beta testers. A meta: colocar o site no ar, para o público, com domínio próprio e tudo mais no dia 3 de dezembro. Nesta semana, várias pessoas testaram o sistema, acessando a listagem, as páginas de anúncios, submetendo anúncios novos e sobretudo reportando bugs e mais bugs. Este era o objetivo. Nos final de semana anterior à minha data limite de “lançamento”, passei horas e mais horas escrevendo código, debugando, testando.

No dia 3, o Job4Dev estava no ar. O Log4Dev ganhou um irmãozinho, e eu ganhei mais um filho. Como disse anteriormente, fazia muito tempo que não tinha tanto prazer em fazer algo relacionado a software. Não pela complexidade do sistema em si, mas pelo fato de ter uma meta a ser alcançada, e de produzir um sistema pequeno, leve, eficiente e útil. E sobretudo de ter a sensação de ter gerado algo que pode ser útil para resolver um problema real.

Google Chart API

Na série “pequenos serviços que a Google oferece gratuitamente en passant e que podem ser uma mão na roda”, acabei de ver o anúncio do Google Chart API. Simples: crie uma URL, e o Google te retorna uma imagem com um gráfico.

Alguns exemplos, criados dinamicamente:

http://chart.apis.google.com/chart?cht=lc&chs=200x125&chd=s:helloWorld

http://chart.apis.google.com/chart?cht=lc&chs=200x200&chd=t:50,20,60,10,5

Não que isto seja a última bolacha do pacote, existem muitas boas APIs para gerar gráficos por aí open source. Mas pode ser útil para quem não pode instalar coisas no servidor e precisa de gráficos simples. A API oferece gráficos de linha, puiecharts, gráficos de Venn, gráficos de barras, gráficos de pontos e outros.

E a API está bastante bem documentada: http://code.google.com/apis/chart/ .

Python

Python

De XKCD

Next Page »