Categories
Etc.

A volta dos que não foram

Um ano sem postar aqui. Um ano! Já passou da hora de sacudir a poeira.

Muita, muita coisa mudou desde o último post. Mudei para os Estados Unidos, trabalhei em vários projetos diferentes, viajei bastante, perdi uns 40 quilos (mas aqui nos EUA eu falo que perdi 80 pounds para parecer mais grandioso!), tive mais uma filha, fiz um “double-double” na liga de basquete do Yahoo! hoje… Tanta coisa aconteceu que fica até difícil de decidir por onde começar.

Fazendo uma retrospectiva rápida, o resumo desse últimos 12 meses é que aprendi mais do que em qualquer outro ano da minha vida. Consegui construir um dos times mais competentes que já participei, fizemos um projeto do zero que é o ponto central de todo o Yahoo!, sem contar os outros que continuamos, até chegar nesse ponto onde estamos hoje, trabalhando num produto que tem mais usuários do que habitantes no Brasil! Dá para passar dias escrevendo sobre isso tudo.

Para poder focar nesses projetos e na minha vinda para os EUA (e na saúde, e na família), tive que sumir um pouco e não fui em nenhum evento depois do BrazilJS em Maio/2011. Fiquei triste também de ter que cancelar algumas palestras que já estavam marcadas em conferências como a QCon e a Codestrong, mas olhando para trás acho que isso foi essencial para permitir colocar 100% do cérebro trabalhando nas coisas mais importantes. Quem sabe em 2013 (se o mundo não acabar antes)…

A boa notícia é que agora as coisas estão mais estabilizadas e estou ansioso para voltar a discutir sobre as coisas que acontecem por aí. Para mim sempre foi muito bom escrever porque me fez aprender ainda mais, não só sobre tecnologia e trabalho como também sobre português (principalmente graças a alguns caras como o Denilson e o Pedro que sempre me mandam correções por e-mail quando escrevo errado). 🙂

Está na hora de organizar as ideias novamente e começar a postar. Estou de volta!

Update: Para tirar a poeira do meu outro blog (em inglês), acabei escrevendo o primeiro post por lá.

Categories
Fun REST Ruby

Cadê meu Sedex?

Quem usa o serviço de Sedex e encomendas dos Correios sabe como é um saco entrar no site dos Correios para saber onde está sua encomenda. Como eu vendo e compro bastante coisa no Mercado Livre, há alguns anos desenvolvi um widget para Mac OS X que facilita buscar essas informações, mas acabei não usando muito porque não era prático o suficiente.

Na sexta-feira passada conversando com uns amigos tive a idéia de fazer um brincadeira no Twitter que poderia ser uma solução suficientemente prática: você digita no Twitter @cade_meu_sedex SO376590583BR” (usando o número da sua encomenda ao invés do meu, obviamente) e o macaco dos Correios diz pra você qual é o status mais recente disponível no site dos Correios. 🙂

cade_meu_sedex

Fazendo essa brincadeira acabei desenvolvendo uma API Ruby e de webservices REST para consulta ao site dos correios, que foi batizada com o misterioso nome de “correios-api”. Essa API já está disponível como uma RubyGem e no site do projeto tem instruções para instalação e uso.

Tanto o robô quanto a API foram desenvolvidos em Ruby e os códigos estão no meu Github para quem quiser dar uma olhada. No caso dos webservices foi especialmente ridículos fazê-los usando o Sinatra, que é um framework sensacional e absurdamente simples.

A próxima feature desse projeto será criar métodos para fazer orçamento de encomendas, que foi uma idéia dada pelo pessoal da lista Rails-BR. Se alguém tiver outras idéias ou quiser colaborar seja bem-vindo!

Categories
Python

Explorando metaprogramação em Python: django-supermodels

Esses dias trabalhando com Python comecei a me perguntar se seria possível fazer no Django alguma coisa parecida com os finders dinâmicos do Rails.

A maioria das pessoas que lêem esse blog devem saber do que se trata mas em todo caso funciona assim: se uma classe Person do model do Rails tem uma propriedade “name” e outra propriedade “country”, você ganha automaticamente uma série de métodos dinâmicos para buscas por objetos dessa classe:

Person.find_by_name("Guilherme")
Person.find_by_country("BR")
Person.find_by_name_and_country("Guilherme", "BR")
# e outros...

Tudo isso é possível graças à funcionalidade de method missing do Ruby. Quando um método que não existe é invocado em uma classe, uma exceção do tipo NoMethodError é lançada. Alternativamente você pode implementar na sua classe o método method_missing, que é automaticamente invocado quando são invocados métodos que não existem.

class Exemplo
  def method_missing(metodo, *args)
    puts "Chamou '#{metodo}' com os params. '#{args}'"
  end
end
Exemplo.new.um_metodo_qualquer("teste")
 
# retorna: 
# "Chamou 'um_metodo_qualquer' com os params. 'teste'"

Usando essa funcionalidade foi possível fazer o tratamento dessas chamadas find_by_* traduzindo para chamadas comuns ao método find(…) com parâmetros.

Na minha pesquisa para ver se isso era possível em Python, acabei criando o projeto django-supermodels (créditos ao Ramalho pelo nome infame), que é uma extensão dos models do Django para prover essa funcionalidade.

Para minha surpresa foi trivial implementar exatamente a mesma coisa em Python usando o método __getattr__, que também é invocado caso um método/atributo não exista:

class Exemplo(object):
  def __getattr__(self, metodo):
    def method_missing(*args):
      print "Chamou '%s' com os params. '%s'" % (metodo, args)
    return method_missing
Exemplo().um_metodo_qualquer("teste")
 
# retorna:
# "Chamou 'um_metodo_qualquer' com os params. '('teste',)'"

Foi um pouco mais difícil fazer isso funcionar dentro do Django, porque a classe django.db.models.Model é construída de uma forma muito estranha que dificulta demais que a minha classe simplesmente herde da classe do Django. No fim das contas acabei criando os finders dinâmicos no manager, que é o objeto que dá acesso às buscas de objetos no banco de dados. Ficou assim:

Person.objects.find_by_name('Guilherme Chapiewski') 
Person.objects.find_by_id(2)
Person.objects.find_by_name_and_id('Guilherme Chapiewski', 2)
Person.objects.find_by_id_and_name(2, 'Guilherme Chapiewski')
 
Person.objects.find_by_nonexistingfield('something')
# Cannot resolve keyword 'nonexistingfield' into field.
# Choices are: age, birth_date, country, id, name

Estou trabalhando para não precisar usar o “.objects” assim como é no Rails, mas isso está dando um pouco mais de trabalho porque envolve entender melhor a forma que o model é criado dentro do Django. Depois disso vou trabalhar também em algumas opções mais poderosas de finders para poder justificar de verdade seu uso.

Antes que alguém fale, não estou tentando transformar o Django em Rails, estou apenas criando um extensão do model que eu acho bem legal e útil, e que você pode usar ou não. 🙂

O código fonte está disponível no meu Github. Já é possível usar esse plugin no seu projeto Django bastando apenas instalar o egg do projeto. Para isso, baixe o código fonte e execute “sudo python setup.py install”. Para saber como usar, veja a aplicação Django “example” que está incluída no código fonte.

Como esse projeto nasceu de um código de estudo está um pouco desorganizado, mas pretendo resolver isso em breve.

Sugestões são bem-vindas!

Categories
Python

Apresentando: simple-db-migrate

Desde o fim do ano passado tenho me divertido um bocado desenvolvendo em Python e Django.

Apesar de ter alguns detalhes esquisitos (especialmente na implementação de OO), Python é uma linguagem sensacional e muito produtiva! O Django também é ótimo e não deixa nada a desejar para o Rails, porém, as comparações são inevitáveis. Uma das coisas que mais senti falta desenvolvendo com Python/Django foram as migrations do Rails. Na verdade, pra quem está acostumado as migrations também fazem falta em Java, PHP e basicamente em qualquer projeto que os bancos de dados são constantemente modificados e complicados demais para serem gerenciados manualmente, independente da linguagem.

Foi por isso que decidi começar o projeto simple-db-migrate. Inicialmente o objetivo era criar algo parecido com as migrations do Rails para o Django, mas agora o objetivo é (além disso) criar migrations para o que quer que seja.

Para isso ser possível as migrations usam DDL ao invés de uma DSL em Python:

Arquivo: 20090215224601_criar_tabela_pessoas.migration

SQL_UP = """
create table pessoas (
    id int(11) not null auto_increment,
    ... etc. ...
);
"""
SQL_DOWN = """
drop table pessoas;
"""

Na verdade, como as migrations são nada mais do que duas Strings Python (SQL_UP e SQL_DOWN), é possível executar qualquer código Python nas migrations que gerem SQL. No futuro isso irá me ajudar a implementar alguma coisa que use os models do Django para criar a DDL automaticamente.

O fato das migrations serem em DDL faz com que eu possa escrever migrations para qualquer tipo de projeto, independente da linguagem e mesmo que no futuro as migrations também possam ser feitas usando uma DSL Python.

Para ver o simple-db-migrate funcionando, depois de instalá-lo (instruções no site), basta ir para o diretório onde estão as migrations e executar:

db-migrate

Se você não quer ter o trabalho de escrever as suas migrations, no diretório “example” tem uma porção delas prontas. Além das migrations é necessário criar um arquivo “simple-db-migrate.conf” com as configurações do banco de dados:

HOST = "localhost"
USERNAME = "root"
PASSWORD = ""
DATABASE = "migration_example"

O arquivo pode ter outros nomes e não necessariamente você precisa estar no diretório das migrations, basta passar essas configurações para o db-migrate pela linha de comando:

db-migrate --dir=migrations_dir --config=path/to/file.conf

Ou output é algo assim:

$ db-migrate --dir=example --config=example/sdbm.conf
 
Starting DB migration...
- Current version is: 20090211120000
- Destination version is: 20090212120000
 
Starting migration up!
 
===== executing 20090211120001_add_user_age.migration (up) =====
===== executing 20090211120002_add_user_mother_age.migration (up) =====
===== executing 20090211120003_create_table_chimps.migration (up) =====
===== executing 20090212120000_create_table_aleatory.migration (up) =====
 
Done.

E por último, já que eu ainda não tenho muita documentação disponível ainda, para ver todas as opções possíveis da linha de comando basta digitar:

db-migrate --help

O simple-db-migrate ainda está em fase embrionária (na verdade comecei na semana passada), mas já está entrando em uso essa semana em dois projetos na Globo.com, ou seja, possivelmente ele vai evoluir bem rápido. Apesar de ainda ser bem simples, tudo que eu mostrei aqui já funciona.

Agora há pouco criei uma versão inicial da página do projeto no Github pages com algumas instruções para instalação e uso (bem simples mesmo, ainda pretendo melhorar bastante). O código fonte está disponível no meu Github e os tickets podem ser acompanhados no Lighthouse.