Nova versão do site
Ao meio-dia do dia 19 eu atualizei este site mais uma vez, com algumas novidades que vinham sendo feitas em doses homeopáticas havia bastante tempo. Seguem abaixo os motivos e meios de como isso aconteceu e quem sabe você possa também aproveitar dessa experiência.
Mais social

O primeiro motivo que me levou a querer mudar o meu site pessoal foi torná-lo mais social. Isso é porque a versão antiga não fazia sequer menção ao livro Aprendendo Django no Planeta Terra, ao meu Twitter ou a nenhum de meus espaços em redes sociais.
Numa Internet cada vez mais social, nerds como eu costumam participar de vários canais ao mesmo tempo, trocando ideias e publicando conteúdo em diferentes lugares, e isso cria um problema crescente: juntar tudo isso num só lugar para que pessoas que acompanham o meu trabalho possam de fato fazê-lo.
Isso já não é mais um problema só de geeks. É cada vez mais real para empresas e profissionais que participam ativamente da Web 2.0 (ou queiram fazê-lo).
Grande parte dos serviços que usamos, como Twitter, Picasa, Flickr, etc. oferecem widgets para integrar em sites, mas o preço que se paga é ter uma caixa completamente diferente do restante do layout, sendo carregada via JavaScript e com propagandas indesejadas.
Solução rápida: RSS - quando disponível - ou apenas links para casos menos importantes.
Para isso eu criei um código [10], cuja função deve ser adicionada à setting TEMPLATE_CONTEXT_PROCESSORS.
As constantes TWITTER_URL e PICASA_URL devem adaptadas para cada caso. No caso do Twitter a URL é a fornecida como RSS da sua conta, e no caso do Picasa, basta trocar ‘marinho’ pelo ID da conta e o número após ‘albumid’ deve ser trocado pelo album que você desejar (ou simplesmente remover a string ‘albumid/NUMERO’ para visualizar todas as fotos da conta.
Observe que tudo em feito em modo Lazy, ou seja, só é carregado quando necessário, armazenado em cache, que expira em 1800 segundos (30 minutos).
Casos onde eu queria apenas linkar (por ora) bastou criar a seção /social/ e pronto :)
Saindo do Google App Engine

Outro motivo bastante considerado foi tirar o site do Google App Engine.
O serviço de hospedagem do Google não tem tido o mesmo desempenho de antes, especialmente para imagens, e isso vinha me incomodando. Junta-se a isso o fato de erros obscuros ocorrerem de vez em quando sem nenhum motivo aparente e a solução também aparecer 2 dias depois sem explicações e você tem mais um motivo considerável.
Aí vem aquele incômodo crescente coma dependência do Google que eu cultivei ao longo dos anos, os constantes ataques à minha conta pessoal no Gmail e foi um motivo real para começar a tirar algumas coisas de lá.
Migrando o código
Mas como migrar para o ORM do Django, sistema de cache e outras coisas?
O segredo foram os cuidados que tomei quando criei as aplicações. Diversas funções que um dia poderiam ser úteis no Django convencional foram feitas sob a égide do DRY, de forma que apenas algumas linhas fossem suficientes para adaptá-las. Sendo assim, funções de publicação de mensagens, envio de e-mails, decorators de templates, gravação de cache e outras funções foram facilmente convertidas.
Desta forma a adaptação do código-fonte se resumiu a ajustar o decorator de cache, mudar os nomes dos tipos de campos (ex.: db.StringProperty() para models.CharField(max_length=N, blank=True)).
Migrando os dados
Mas como você já deve ter imaginado, o maior problema não é o software, e sim os dados.
O BigTable é completamente incompatível com bancos relacionais, e o Google não disponibiliza nenhum serviço oficial de dumping.
Uma das soluções é o bulkloader [8], disponibilizado como parte do SDK. Para mim não atendeu pois eu queria uma solução mais rápida, sem precisar codificar mais.
Outra solução é o Gaebar [9], que faz a transferência dos dados de uma forma mais sutil, em pacotes pequenos, do servidor de produção para o servidor local, também não funcionou bem pra mim.
Então a solução que adotei foi gerar os dados em formato JSON e importá-los com outro código. Foi bastante simples e resolveu, mas esta solução não atende se o volume de dados for grande o bastante para exceder o limite de tempo da requisição que o Google App Engine permite.
Alternativa de hospedagem na cloud
Escolhi a Rackspace [11] para meu serviço de hospedagem predileto. Os custos estão bem mais baixos do que a concorrência, o desempenho tem superado a Amazon WS e Google App Engine de longe, e a facilidade de iniciar uma máquina virtual e começar a usar foi muito satisfatória.
O melhor custo/benefício que encontrei. Recomendo.
Atualização para Django 1.2

A versão 1.2 do Django consagra o jQuery e o CSRF, suporta múltiplas conexões com o banco e corrige o velho sistema de mensagens, fora outras novidades.
É claro que alguns projetos que eu toco vão ter que esperar para migrar para a nova versão, mas já havia algum tempo que eu vinha atualizando a maioria deles, e não seria diferente neste caso. As mudanças não impactaram quase nada e bastou implementar o CSRF para ficar tudo ok.
Sendo assim, a implementação do CSRF se resume a duas coisas:
Encapsular views sob o decorator @csrf_protect, assim:
from django.views.decorators.csrf import csrf_protect ... @csrf_protect def minha_view(request): ...E no template, acrescentar o parametro de verificação, assim:
{% csrf_token %}
Essa mudança reforça diretamente a segurança dos formulários contra ataques de requisições falsas de sites duvidosos.
Atualização para HTML5 e CSS3

Nos próximos anos a Web vai respirar HTML5, e com ele vem junto o CSS3, as fontes OTF, o formato multimídia OGG, sessões de longa duração, WebSockets e assim por diante.
Como sabemos, o calo no pé dos desenvolvedores Web sempre foi e continua a ser o Internet Explorer. De acordo com este site [3] a versão 9.0 do I.E. ainda vai ser incompatível o bastante para incomodar e “freiar” caras como eu, que adoram novidades.
Mas eu decidi que esse não seria um empecílio.
Para começar, criei um fork [4] do django-html5 [5]. Este projeto implementa suporte aos novos inputs do HTML5, mas eu precisava de outro conjunto de funcionalidades, baseando na necessidade de detectar se o navegador do usuário é compatível com HTML5 e sendo assim, priorizar templates com extensão .html5 antes dos homônimos com extensão .html.
Desta forma, as funcionalidades que implementei permitiram que, ao detectar um navegador incompatível, o template antigo é renderizado e mostrado para o usuário.
Abrindo mão dos middlewares e decorators de cache do Django
Eu já havia comentado isso aqui, em outro artigo, mas eu melhorei bastante o decorator, que substitui o @cache_page, e tem o mesmo nome.
O conjunto de caching de requests do Django é um tanto incompatível com cache invalidation, e a solução que mais se aproximou de casar uma coisa com outra foi esta [1] e como podem ver, não foi das melhores.
Por isso eu implementei o meu próprio decorator [2] e o melhorei ao passar do tempo.
O decorator se baseia somente na URL e na compatibilidade do navegador com HTML5 para montar a chave do cache. O Django usa um hash do cabeçalho do HTTP, e é exatamente isso que torna complicado o processo de saber qual é a chave respectiva a uma determinada URL.
O decorator basicamente funciona da mesma forma que o do Django, mas ao criar a chave para gravar no cache, ele verifica se o navegador é compatível com HTML5 e acrescenta isso à chave.
Para forçar a o cache invalidation, basta saber a URL e chamar a função invalidate_cache. Desta forma, seu timeout de expiração pode ser de quanto tempo quiser, por exemplo: 24 horas, 10 dias, enfim. Se fizer direitinho o cache invalidation, o tempo de expiração pode ser o mais longo possível.
Template inspirado no Woo Irresistible

Por fim, justiça seja feita. O layout foi criado com base no template Irresistible [6], da Woo Themes [7].
Fora isso, mantive a tradição do rosa, mas agora pegou uma cor mais escura, caminhando pro vinho. Gostei :) Referências externas
Referências externas
| [1] | http://blog.apps.chicagotribune.com/2009/11/02/off-process-cache-invalidation-in-django/ |
| [2] | http://djangosnippets.org/snippets/1493/ |
| [3] | http://caniuse.com/ |
| [4] | http://github.com/marinho/django-html5 |
| [5] | http://github.com/rhec/django-html5 |
| [6] | http://www.woothemes.com/2009/02/irresistible/ |
| [7] | http://www.woothemes.com/ |
| [8] | http://code.google.com/appengine/docs/python/tools/uploadingdata.html |
| [9] | http://aralbalkan.com/1837 |
| [10] | http://pastebin.com/7rRqawxU |
| [11] | http://rackspace.com/ |