Fibonacci: alguns algoritmos efetivos em AWK

Estava apreciando hoje de manhã um post do Felipe Tonello: Analisando Número de Fibonacci e Recursividade. É um bom artigo sobre aquelas coisas que alguns podem ter visto na faculdade e são sempre uteis: matemática, analise de algoritmos e um pouco de mente aberta.

Imediatamente tratei de testar a velocidade dos dois algoritmos propostos usando AWK (que, por ser interpretado, pode revelar melhor as nuances entre as abordagens). Algoritmos recursivos são interessantes, principalmente quando trabalhamos com linguagens funcionais, porém algumas formas tem um custo computacional muito alto e o calculo de Fibonacci é um exemplo perfeito: para cada termo eu preciso calcular os dois termos anteriores e, então, soma-los, e isso cresce geométricamente, consumindo memória e processamento, sem falar que tenho muita repetição de código desnecessária.

A tecnica de programação dinâmica apresentada cria um cache de resultados, dessa forma evito boa parte do trabalho extra, veja o resultado:

Fibonacci(36) pelo algoritmo recursao simples:14930352 usando 48315633 iteracoes

real    0m51.961s
user    0m23.881s
sys     0m0.012s
Fibonacci(36) pelo algoritmo programacao dinamica:14930352 usando 71 iteracoes

real    0m0.002s
user    0m0.000s
sys     0m0.000s

Usando programação dinâmica eu uso muito menos de 1% do processamento necessário pela forma recursiva tradicional. Parece ótimo, não? Depende, pois eu apenas afastei o problema: ao calcular termos de alta ordem eu terei o mesmo problema, afinal o algoritmo é O[n].

Lembrei de um post do Ronaldo Melo Ferraz, Conceitos de Programação: Tail Recursion enquando estava testando os algoritmos em Erlang e encontrei esta implementação. A adaptação para awk é tranquila e o teste mostrou este resultado:

Fibonacci(36) pelo algoritmo programacao dinamica:14930352 usando 71 iteracoes

real    0m0.002s
user    0m0.000s
sys     0m0.000s
Fibonacci(36) pelo algoritmo tail recursion:14930352 usando 38 iteracoes

real    0m0.001s
user    0m0.000s
sys     0m0.004s

Um resultado ainda mais interessante, pois eu consigo obter o valor do termo com um pouco mais da metade das iterações do que usando programação dinâmica (sem onerar a memória com o cache dos resultados).

Esta analise é muito superficial, a ideia é apenas despertar a curiosidade sobre estes tópicos.

O codigo fonte utilizado nesse benchmark:
function Fib_normal(N) {
return (N > 1)? Fib_normal(N-1) + Fib_normal(N-2) : N
}
function Fib_dinamic(N) {
if (!m[N]) m[N] = (N > 1)? Fib_dinamic(N-1) + Fib_dinamic(N-2) : N
return m[N]
}

function Fib(N) { return Fib_tr(N,0,1); }
function Fib_tr(I,R,N){
return (I==0)? R : Fib_tr(I-1,N,R+N)
}

Rating 4.00 out of 5
[?]
Publicado em Awk, Dicas | Deixar um comentário

Pesquisa: o que te desmotiva no trabalho?

Nem sempre estamos satisfeito no ambiente de trabalho, seja pelo transito, paredes que dão choques ou projetos malucos que fazem a gente varar a noite.

Pensando no que os meus colegas e eu ja passamos, quero fazer uma pesquisa: alguem ja passou por estas situações e quais são as piores, no sentido de arrebentar com a nossa incrivel motivação no trabalho?
- Falta de equipamentos adequados (quem nunca pensou em comprar um pente de memória com o dinheiro do bolso pra levar pro trabalho);
- Falta de café, chá ou ar condicionado (ou quando tem é ruim);
- Colegas doidos que te levam a loucura;
- Internet bloqueada (incluindo o google);
- Ter que trabalhar depois do horario (as vezes sem receber por isso);
- Codigos que parecem ter saido de um conto de H.P. Lovecraft;
- Projetos que parecem não ter sentido ou importância;
- Chefes que parecem ter saido de uma tirinha do Dilbert;
- Chefes truculentos, desses que da medo falar o nome;
- Resistência a mudanças (riem de Ruby on Rails e desenvolvem em Java como se fosse Cobol);
- Buzzwords são mais importantes do que atender aos clientes;

Os profissionais de informática, especialmente os desenvolvedores, possuem formas de encarar o trabalho que, de acordo com o ambiente, a vontade de fazer algo bom some restando cinismo, péssimo humor e curriculos atualizados prontos para zarpar para outras oportunidades. Algumas vezes é inevitavel, afinal somos humanos, mas o que nos leva a aguentar, enfrentar ou desistir desses problemas?

Uma caracteristica é bem clara: gostamos de fazer coisas especiais. É ironicamente engraçado ver as reações de alguns profissionais quando estão fazendo algo ordináriol, comum ou que julguem sem importância pois muitos odeiam isso, porém estão fazendo por algum motivo: geralmente existe alguma extratégia da empresa que deveria ser respeitada. Creio que este tipo de “soberba” afeta o nosso rendimento pois é muito facil ver reações emocionais e não tanto racionais.

No aguardo da flame-war

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | 16 comentários

RPG em Ruby com apenas 15 linhas

Achei este link bem interessante: MUD in 15 Lines of Ruby. Para quem não sabe MUD é uma familia de jogos textuais inspirados em RPGs conhecidos: normalmente vc escolhe uma raça e uma classe e, dentro do jogo, evolui através da morte de criaturas controladas pelo jogo e através de missões varias como recuperar itens ou decifrar enigmas, são os avós dos MMORPGs modernos.

O codigo foi um tanto obsfuscado, na verdade são umas 77 linhas, mas não deixa de ser interessante o poder das linguagens scripts :)

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | Com a tag , | Deixar um comentário

Desculpas dos Programadores aos Testadores

Muito interessante esta lista das desculpas mais comuns.

De fato eu nunca vi a atividade de teste como uma tarefa para prejudicar o desenvolvimento e sim uma atividade que agrega (em alguns casos, muito) valor. Mas que as desculpas são engraçadas, isso são :)

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | Deixar um comentário

GoogleTalk em Python

Com a biblioteca xmpp eu posso criar o client de Jabber, acessando a rede do GTalk.

import xmpp

login = 'login' # @gmail.com
pwd   = 'senha'

cnx = xmpp.Client('gmail.com')
cnx.connect( server=('talk.google.com',5223) )

cnx.auth(login,pwd, 'python-xmpp')

cnx.send( xmpp.Message( "teste123@gmail.com" ,"Hello World from Python" ) )

Basta incluir a biblioteca (apt-get install python-xmpp) e pronto. O codigo eu me baseei neste artigo. Facil não?

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | Deixar um comentário

Pra descontrair

xkcd code talkers

http://xkcd.com/257/

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | Deixar um comentário

Closures em Javascript: o metodo each

Estou escutando uma discussão acalorada sobre Closures, Ruby e Javascript. Detalhes a parte, Javascript suporta funções anônimas (que não são closures) que podem ser passados como argumentos para outras funções.

Não seria otimo que um Array em javascript tivesse o método each para executar um bloco de código para cada elemento desse array? Usando o prototype da entidade Array eu posso adicionar um método each que faz isso:

Array.prototype.each = function(fun) {
	if (typeof fun != "function") return;
	for (var i=0; i<this.length; i++) {
		if(i in this) fun(this[i]);
	}
	return this;
}

var x = ["cat", "dog", "mouse", "bird"];
x.each(function(i) {
	alert(i);
});

Simples, não? Eu ainda posso adicionar outros métodos uteis como o map e o reduce.

São recursos interessantes que podemos utilizar quando for conveniente. Interessante foi descobrir a propriedade arguments, um array com todos os argumentos passados para a função que, se eu conhecesse alguns meses atrás, teria me solucionado alguns problemas :)

É claro que tudo isso ja vem no Prototype (né peleteiro).

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | Com a tag , | 6 comentários

Algoritmos Geneticos, Videos e VBScript

O Carlo “zED” Caputo ja tinha comentado sobre o uso de Algoritimo Genético para melhorar a qualidade dos vídeos aqui na globo.com, trabalho que rende bons frutos ao procurar profiles que combinem tamanho, qualidade e tempo de encoding. Ao trabalhar com profiles H.264 descobrimos uma coisa interessante: nem todos os profiles tocavam no iPhone. Não havia nenhuma regra aparente para gerar um profile “universal”, então algum tipo de teste mais “hard” deveria ser feito.

Manualmente, vc arrastava o video através do iTunes e o mesmo era aceito ou rejeitado pelo aparelho, tarefa que, se feita manualmente, é muito chata. Como automatizar isso?

Lembrei que muitos programas no mundo windows possuem uma interface COM que pode ser invocada por um vbscript ou mesmo C#. Isso me foi util uma vez quando praticamente reinventei um Selenium para integrar com uma ferramenta de testes muito ‘exotica’, dica retirada do livro .NET Test Automation Recipes: A Problem-Solution Approach. Nosso amigo google ajudou a localizar uma prova de conceito ao fazer a pesquisa “itunes vbscript”:

iCame, iPod, iScripted: Scripting iTunes

Era o que eu precisava. Talvez vcs estejam curiosos sobre vbscript ao inves de Jscript: é mais comum usar vbscript para esse fim pelo mundo afora, uma vez que COM é confundido com .com das urls pela busca do google.

Set objApp = CreateObject("iTunes.Application")
Wscript.Echo "Version: " & objApp.Version

Como podem ver, é muito simples. Existe um SDK desenvolvido pela Apple para trabalhar com o iTunes que é muito bem documentado e me ajudou muito. Bastava agora saber como adicionar os videos e capturar quando ocorre uma rejeição ou não.

Detalhes a parte, quando enfrentamos esse tipo de desafio precisamos pensar em termos de manutenção de codigo: como criar um script que tenha vida loga? Decidi usar as tecnologias mais comuns e ser o mais claro possivel (por isso vbscript, que não é tão tosco assim).

A integração com o Algoritmo Genetico foi feita usando um serviço assíncrono cuja integração era feita atraves do filesystem: bastava copiar um arquivo para um diretorio que um .bat do windows tomava conta do recado, disparando o vbscript. Foram necessarios algumas tentativas até chegar a uma estabilidade aceitável, pois acontecem coisas bem interessantes quando vc acessa uma aplicação via COM, principalmente quando um dispositivo esta ligado à USB e vc faz muitas vezes a mesma coisa. Como os serviços eram assincronos eu conseguia paralelizar parte das tarefas e, se precisasse escalar e testar em 2 ou mais aparelhos seria só desenvolver um sistema de lock apropriado (para 2 scripts não tentarem mover o mesmo arquivo).

Tirando o fato que eu tive q fazer coisas não-canônicas como usar o ping para localhost para simular um sleep (ok, considere isso como uma resposta ao select undef, undef, undef, 0.5;), foi divertido.

Esta estratégia pode ser usada em muitas coisas do mundo Windows, existem muitos exemplos pelo google afora e, se vc deseja algo mais profissional, basta usar o Visual Studio e programar em uma linguagem decente que compila e possui frameworks de teste unitários.

Rating 4.00 out of 5
[?]
Publicado em windows | Com a tag , , , | 3 comentários

Trabalhando com Serviços Assíncronos

Geralmente desenvolvemos serviços síncronos, mesmo quando uma grande quantidade de etapas precisa ser executada, em detrimento de serviços assíncronos.

Imagine um sistema que, em dado momento, precisa enviar emails. Podem ser aqueles emails para convidar outras pessoas para usar a plataforma, algo que vc faz uns 50 ou 100 de uma vez. O desenvolvimento natural é ler essa lista de emails e, iterativamente, enviar um convite para cada pessoa (com algum codigo que identifique esse convite para evitar fraudes, por exemplo). Coisa que, dependendo do numero de emails e como cada passo é processado pode demorar um pouco.

Precisa ser síncrono? Vc precisa enviar esses convites naquele momento? Faz diferença se demorar uns minutinhos? Como esta solução sincrona afeta a performance do resto da minha aplicação (coisa que posso avaliar num teste de carga)? São perguntas que podemos nos fazer e dão algumas pistas, abrindo alas para a verdadeira pergunta: como a minha aplicação escala?

Se esta etapa pode demorar um tempinho e ela afeta (ou pode afetar) negativamente a experiência do usuario ao demorar para enviar 50 ou 100 convites, pode ser o momento de separar a minha aplicação do serviço de ‘convites por e-mail’, que ira trabalhar assincronamente sem concorrer tanto com CPU (ex: usando nice ou rodando em outro servidor). A minha aplicação apenas iria dizer “essas são as informações: nome do usuario e lista de emails para convites” que o sistema sabe se virar.

E como essa integração é feita? Existem varias formas. Eu posso fazer através do banco de dados, inserindo numa tabela que o meu sistema lê, porém integração pelo banco nunca é algo simples e frequentemente causa problemas (principalmente se a documentação se perde e altera alguma coisa no banco, prejudicando outras aplicações que ninguem sonha que trabalhem assim). Uma boa forma seria passar uma mensagem com todos os dados para o servidor de alguma forma inequivoca, como um POST HTTP (que retorna “ok, recebido, logo vou processar isso”) ou, simplesmente, escrevendo num arquivo em um determinado diretorio. O serviço trata de ler essa requisição e colocar em uma fila ou outra estrutura de dados para atender no prazo que for possivel.

No caso de uma lista de emails escrever em um arquivo parece grosseria mas se eu estivesse trabalhando com fotos, em um serviço de geração de thumbnails, por exemplo, parece ser uma saida bem simples. Nesse caso em particular eu posso criar um “vigia de diretorios”, alguem que vigia uma pasta de tempos em tempos e, quando surge algo novo, executa alguma ação propriamente dita. A forma como eu trabalho pode ser bem simples, como: acordar, listar fotos, executar ação, apagar fotos. Se eu quiser trabalhar com uma maquina de estados eu posso criar pastas como: chegada, processando, fim. O serviço trata de olhar a pasta de chegada e, quando precisa, move as fotos ou outras entidades para o diretorio processando e, então, executa alguma ação.

Nesse ponto algumas coisas precisam ser acertadas: se eu vou trabalhar com estados das minhas fotos, convites, ou qualquer outra entidade, posso modelar este serviço de forma que, se a minha entidade esta na pasta X, então ela tem um determinado estado. Isso é interessante pois caso o meu serviço seja interrompido basta mover tudo o que estava sendo processado para a pasta de chegada! Nesse ponto temos que ter bem claro o que acontece em cada transição de estado, os fluxos possiveis e estabelecer os corretos tratamento de erros.

Se tudo der certo, eu posso rumar para uma aplicação que, para escalar, bastaria subir um segundo serviço em outra maquina (ou aproveitando outra CPU). É claro que existem muitas outras formas de chegar a este resultado e muitas tecnologias disponiveis, porém soluções simples e robustas são sempre bem vindas: percebam que existem muitos pontos de falha que temos que tratar então com a suites de testes apropriada e uma documentação consisa podemos ter um bom serviço assincrono que só vem a agregar valor.

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | 9 comentários

Inversão de Controle e Injeção de Dependências

Fui surpreendido por uma pergunta hoje: o que é IOC (inversion of control)?

Lembrei agora que um bom exemplo de IOC é programação orientada a eventos: lembram daquelas telas de Visual Basic que criavamos arrastando os componentes e adicionando codigo no “onClick” de um botão? Isso é uma forma de IOC pois não criamos o código que, dado o clique em um determinado componente, executa a ação, apenas jogamos um trecho e deixamos que a IDE “se virasse” para adicionar aquilo ao programa principal. Assim deixamos de controlar todo o fluxo para controlar uma parte dele.

Podemos pensar que IOC tem haver com “o que” e não, diretamente, “como”. Uma leitura interessante é o artigo do Martin Fowler intitulado Inversion Of Control – Containers de Inversão de Controle e o padrão Dependency Injection, com exemplos em Java.

Rating 4.00 out of 5
[?]
Publicado em Uncategorized | Deixar um comentário