Novo ano e novos ventos

Após iniciar um novo ano, muita gente escreve aquelas listinhas cheias de tarefas a realizar durante a jornada que se inicia e comigo não poderia ser diferente. Desenvolvi essa mania nos últimos anos e acho bastante gratificante ter a possibilidade de fazer uma retrospectiva e ver que muito se fez, decisões tomadas que alteraram alguns objetivos, portas que se abriram e outras que se fecharam, entre outros tipos de análises. E como parte dessas resoluções de ano novo, estou fechando esse domínio e concentrando todas as fontes de conteúdo que eu gero em apenas um lugar. O meu novo site pessoal será o destino de todos os meus artigos técnicos, minhas pesquisas na área de marketing digital, minhas observações no que tange ao comportamento humano, minhas observações políticas e tudo mais que eu achar relevante.

Aos que se acostumaram a consultar este espaço, todo o conteúdo aqui presente foi migrado para o novo domínio, assim como os amigos do Google Friend Connect. Deixarei o espaço mais alguns dias funcionando e em breve farei redirecionamento para o novo site. Tenho certeza que fazendo isso, conseguirei focar muito mais nas mensagens que desejo passar. Lembrando que o site ainda está sendo construído, de forma incremental :D .

Ah, e claro que eu não vou esquecer de divulgar o novo domínio, muito menos o novo Feed RSS. Segue abaixo.

www.felipepavao.com e feeds.feedburner.com/felipepavao

Acesse, divulgue, critique. Abraços e até lá.

Adicionando dados ao banco corretamente com Rails

Essa dica é rápida porém muito eficaz. No Rails 2.3.4 foi adicionado uma funcionalidade para podermos popular nossa base de dados de forma segura e correta, pois antes tínhamos que criar migrations de dados de exemplo ou até mesmo os primeiros dados de configuração da aplicação.

Agora basta criar um arquivo chamado seeds.db dentro da pasta db da sua aplicação. Nele você pode chamar os objetos Rails normalmente como o código abaixo:

 
puts "Adicionando usuario admin"
u = User.new(
            :email => "admin@testecom",
            :login => "admin",
            :password => "12345",
            :password_confirmation => "12345",
            :admin => true
            )

Para rodar a massa de dados basta executar:

rake db:seed

Não está mais fácil e organizado ? Até a próxima.

SQLAlchemy e memcached

Quando falamos de aplicações de alta perfomance, falamos basicamente em cache, cache e mais cache. E então, nos deparamos com a seguinte pergunta: como integrar uma ferramenta de mapeamento de objetos relacionais (ORM), que mantém associação e relacionamentos entre objetos em sessão, com uma solução de cache, como o memcached ? Complicou ? Então acalme-se, pois iremos explicar como fazer de uma forma limpa e elegante.

Para começar vamos falar um pouco do ORM SQLAlchemy, que estamos utilizando em um projeto. O SQLAlchemy é um framework python responsável por transformar suas tabelas em objetos relacionais, a fim de abstrair todo acesso ao banco, dando total flexibilidade ao desenvolvedor. Está atualmente na versão 0.5.6 e entre suas principais features estão, pool de conexões e gerencia de sessão. Nosso foco aqui não é se aprofundar no SQLAlchemy, mas sim em como integrá-lo com o memcached.

O grande gargalo das aplicações atualmente é, sem dúvida, o acesso ao banco, e para resolver esse problema nós utilizamos cache em memória, a fim de evitar acessar o banco toda vez que se quer ter acesso a alguma informação. O problema é que quando utilizamos um ORM, ele fica responsável pelo acesso ao banco e você perde o controle sobre as operações realizadas. O que nós queremos é ter o poder de um ORM, aliado ao poder do cache, e a solução passa por criar uma abstração no SQLAlchemy, que verifique se um determinado objeto está no cache, e ir ao banco somente se o ele não existir em cache.

Isso pode parecer simples, mas o SQLAlchemy na atual versão, mantém os objetos em sessão, para aumentar a performance, evitando ir ao banco sempre que um objeto é requisitado pela aplicação, e somente ele tem o controle desses objetos. Imagine que tenhamos uma associação simples entre jogador e clube, onde um jogador pertence a um único clube. Vejamos o exemplo abaixo:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy import create_engine
 
Base = declarative_base()
class Jogador(Base):
 
    __tablename__ = 'jogador'
 
    id = Column('jogador_id', Integer, primary_key=True)
    nome = Column('nome_txt', String)
    clube_id = Column('clube_id', Integer, ForeignKey("clube.clube_id"))
    clube = relation(Clube, backref="jogadores")
 
# cria uma sessão com o banco
engine = create_engine('mysql://root:@localhost/teste', echo=True)
session = scoped_session(sessionmaker(bind=engine, autocommit=True, autoflush=True))
 
jogador = session.query(Jogador).get(id) #recupera o jogador de id=1
clube = jogador.clube #recupera o clube do jogador
print "o nome do jogador e %s" %clube.nome

Ao procurar por um jogador, o ORM verifica se ele está na sessão, se não estiver ele irá executar um SELECT no banco, o mesmo acontecendo com o clube. Entretanto, nós desejamos que antes dele fazer acesso ao banco verifique se o mesmo está em cache. Para isso precisamos sobreescrever o objeto query da sessão do SQLAlchemy, criando uma classe, CachedQuery, que extende sqlalchemy.orm.query.Query e implementa essa lógica.

import memcache
from sqlalchemy.orm.query import Query
 
cache = memcache.Client(['127.0.0.1:11211'], debug=0)
 
class CachedQuery(Query):
 
    def get(self, ident, **kw):
 
        mapper = self._mapper_zero()
        session = self.session
 
        # gera uma chave para o objeto
        key = mapper.identity_key_from_primary_key(ident)
 
        # pega o objeto da sessão, se existir
        cacheobj = session.identity_map.get(key)
 
        # gerando uma chave para o memcached module.Classe(id)
        cache_key = "%s.%s%s" % (key[0].__module__,key[0].__name__,key[1])
 
        if not cacheobj:
 
            # pega o objeto do memcached, se existir
            cacheobj = cache.get(cache_key)
 
            if cacheobj is not None:
                # recuperando do cache e setando na sessao
                cacheobj.__dict__["_sa_instance_state"] = attributes.instance_state(cacheobj)
                session.add(cacheobj)
            else:
                # nao existe no cache, pega do banco
                cacheobj = super(CachedQuery, self).get(ident)
                if cacheobj is None: 
                    return None 
                # setando objeto no cache
                cache.set(cache_key, cacheobj)
        else:
            # recuperando da sessao
            pass
 
        return cacheobj

Perceba que ao extender Query e sobreescrever o método get, estamos alterando apenas o seu comportamento, não interferindo no resto da classe. Poderíamos sobreescrever também os metodos save, update e delete, para salvar, atualizar e remover o objeto também do cache. Depois de criada a classe CachedQuery basta instanciar a sessão do SQLALchemy, utilizando essa classe. voltando ao nosso exemplo do jogador a create_session ficaria da seguinte forma

 
..
 
# cria uma sessão com o banco
engine = create_engine('mysql://root:@localhost/teste', echo=True)
session = scoped_session(sessionmaker(bind=engine, autocommit=True, autoflush=True, query_cls=CachedQuery))
 
...

A partir daqui todo acesso ao banco passará antes pelo memcached aumentando de forma exponencial a performance de sua aplicação.

Localização e Rails 2.3

De vez em quando somos desafiados a desenvolver projetos que necessitam de traduções para outras línguas. Para resolver isso, usamos técnicas de localização.O Rails facilita muito a nossa vida ao guardar mensagens de erro e todo o texto customizado que você desejar traduzir em apenas um lugar.

Abaixo segue um exemplo de um trecho do arquivo de tradução com mensagens de erro do Active Record traduzidos para português:

:activerecord => {
      :errors => {
        :template => {
          :header => {
            :one => "Identificamos 1 erro nesta operação",
            :other => "Identificamos {{count}} erros nesta operação"
          },
          :body => "Por favor, confira os seguintes campos:"
        },
        :messages => {
          :inclusion => "não está incluso na lista",
          :exclusion => "não está disponível",
          :invalid => "não é válido",
          :confirmation => "é diferente da confirmação",
          :accepted  => "precisa ser aceito",
          :empty => "não pode ser vazio",
          :blank => "não pode ser vazio",
          :too_long => "é muito longo (deve ser menor que {{count}} caracteres)",
          :too_short => "é muito curto (deve ser maior que {{count}} caracteres)",
          :wrong_length => "não é do tamanho correto (precisa ter {{count}} caracteres)",
          :taken => "não está disponível",
          :not_a_number => "não é um número",
          :greater_than => "precisa ser maior do que {{count}}",
          :greater_than_or_equal_to => "precisa ser maior ou igual a {{count}}",
          :equal_to => "precisa ser igual a {{count}}",
          :less_than => "precisa ser menor do que {{count}}",
          :less_than_or_equal_to => "precisa ser menor ou igual a {{count}}",
          :odd => "precisa ser ímpar",
          :even => "precisa ser par",
        }
      },

Seguindo o tutorial, para ativar a localização em um aplicativo Rails, basta definir as seguintes configurações em seu arquivo enviroment.rb:

config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
config.i18n.default_locale = 'pt-BR'

Dessa forma, define-se uma linguagem padrão para todo o site. Se quisermos alterar a linguagem durante a renderização das páginas, passando parâmetro na URL, pode-se definir os seguintes parâmetros no application controller.

before_filter :set_locale
 
def set_locale
    # update session if passed
    session[:locale] = params[:locale] if params[:locale]
 
    # set locale based on session or default 
    I18n.locale = session[:locale] || I18n.default_locale
 
    # load locale from settings
    @locale_files = []
    ['yml', 'rb'].each do |type|
      locale_file = "#{LOCALES_DIRECTORY}#{I18n.locale}.#{type}"
      if File.exists?(locale_file)
        @locale_files << locale_file
        I18n.load_path << locale_file
      end
    end
  end

Como viram, é bastante fácil “localizar” em Rails. Se você desejar também traduzir o conteúdo das páginas. Veja o codigo abaixo:

},
      :home => {
        :see_more_link => "Veja mais {{more_link}}",
        :see_all_link => "Saiba tudo sobre este {{all_link}}",
        :video_box_title => "Aperitivo",
        :events_box_title => "Últimos Eventos",
        :blog_box_title => "Blog",
        :followers_box_title => "Fãs",
        :scrapbook_box_title => "Scrapbook",
        :shopping_box_title => "Shopping"
      },

Criamos um dicionário de ítens a serem traduzidos. No template HTML, você deve fazer da seguinte forma:

<h1><%= I18n.t 'txt.home.video_box_title' %></h1>

Mais uma vez comprovamos a facilidade de traduzir com Rails. Para ter o arquivo de localização completo, entre em contato comigo que eu enviarei, pois ainda não disponibilizei no github. Se for urgente, você poderá encontrar em alguns perfis onde achei o modelo para me basear.

Dev in Rio 2009

Dev in Rio 2009

Mais um evento muito legal promete agitar e marcar o cenário carioca de desenvolvimento de software. Será realizado dia 14 de setembro o Dev in Rio, um evento que terá vários ícones nacionais e internacionais representando diversas comunidades de tecnologias. Um dos organizadores é meu colega de trabalho Guilherme Chapiewski, famoso por diversas palestras que já fez em sua carreira, além de ser um grande desenvolvedor.

O evento que também é organizado pelo Henrique Bastos, contará com as presenças de Ryan Ozimeck, Guilherme Silveira, Nico Steppat, Fábio Akita, Jacob Kaplan-Moss, Jeff Patton e Vinícius Manhães Teles.

Confira toda a programação no site do evento e não deixe de participar.

Monitorando memória usada em servidor Linux

Post rápido com dicas de ferramentas para monitorar sua VPS ou algum servidor Linux qualquer que você precise administrar. Todos sabemos que memória é um dos componentes mais críticos em um servidor, pois se houver um problema de congestionamento, as operações realizadas nele podem ser tornar lentas, causando lentidão no website e má experiência na navegação do usuário. Então, saber a quantidade de memória livre é vital para tomada de decisões e para projetar o crescimento escalável das aplicações. Veja abaixo alguns programas úteis.

free -[options]

O programa free exibe a quantidade de memória disponível na máquina e também a memória física (RAM) usada e a livre do sistema. Além disso, exibe também a memória compartilhada, buffer, cache e swap utilizada pelo kernel Linux.

Exemplos:

free -m

Este comando exibe a memória física em MB.

free -m -s 5

Este comando  irá ativar um loop de chamadas com delay de 5 segundos, ou seja, a cada 5 segundos, você terá os valores exibidos no terminal (ou onde você quiser direcionar a saída de tela) em megabytes. Qualquer número pode ser passado.

free -t -m

Igual ao free -t -m com a diferença que o -t exibirá também o espaço disponível para memória swap.

vmstat -[options] [delay count]

O vmstat exibe várias informações sobre memória, sistema e cpu, como swap, memória livre, buffer and memória de cache, espaço para paginação, atividade de IO, traps entre outros.

Exemplos:

vmstat

O comando indicará dados desde o último reboot da máquina.

vmstat 5

O comando indicará dados desde o último reboot da máquina e repetindo a informação de 5 em 5 segundos.

top

O programa top exibe dados em tempo real de acordo com os processos iniciados na máquina. Ele exibe muitas informações, mas podemos destacar sua principal característica como indicar qual processo está consumindo mais processamento e memória, pois estes processos ficam ordenados por ordem de consumo.

ps

O comando ps exibe um snapshot de informações sobere processos ativos. A vantagem do ps é que um administrador pode ver onde a memória é usada, pois ele exibe o percentual de memória que cada processo ativo está consumindo.

Exemplo:

ps aux

Mostra uma série de informações sobre os processos, como PID, percentual de memória consumida, percentual de CPU consumido entre outras informações que te possibilitam monitorar seu sistema de forma satisfatória.

Lançado o novo Tempo Real do Globoesporte.com versão Iphone

Globoesporte Tempo Real Iphone - Tela de Cobertura

Ontem fizemos os últimos testes e colocamos em produção nosso aplicativo web para Iphone de cobertura em tempo real dos jogos de futebol. O aplicativo tem características semelhantes ao original do Globoesporte.com, entretanto, respeita os padrões de desenvolvimento para sites visualizados em dispositivos móveis. Basicamente ele consome as mesmas informações publicadas no aplicativo web Tempo Real original, porém as exibe em um formato customizado para Iphone.

Na verdade, nós já tinhamos esse aplicativo funcionando em uma arquitetura antiga, sob Java + Struts + Jbossweb + Oracle atrelado a todo o conglomerado de sites móveis da Globo.com. O problema é que o aplicativo de Tempo Real, devido ao grande apelo que é futebol, recebia uma grande quantidade de acessos simultâneos, causando lentidão em todos os outros sites.

Globoesporte Tempo Real Iphone - Tela de Escalação

Sugerimos então refazer apenas o aplicativo de Tempo Real, retirando-o da arquitetura antiga e adicionando algumas correções de bug e features, mas desta vez sob a nova arquitetura. Decidimos por Python + Django pois é a direção que a empresa vem adotando para construir novos sites e aplicativos. Com a ajuda do SCRUM, conseguimos refazer todo o aplicativo em tempo (1 sprint), além de entregarmos outras histórias em paralelo, pois aqui na Globo.com, devido ao número de demandas, temos que trabalhar simultaneamente em diversos produtos.

Globoesporte Tempo Real Iphone - Tela de Vídeos

Gostaria de parabenizar a todos do time e espero anunciar neste humilde blog novidades em breve.

Python Brasil 2009 – 5º encontro

PythonBrasil[5]

O maior evento da comunidade Python brasileira está chegando. Renomeado para Python Brasil (antes era Pycon), a Python Brasil 2009- 5º encontro acontecerá em Caxias do Sul, entre os dias 10 e 12 de setembro próximo. As inscrições já estão abertas e você pode conferir no site do evento maiores detalhes.

Estamos pensando em apresentar alguma coisa feita em Django aqui na Globo.com no evento, mas precisamos ver se iremos este ano. Ano passado o evento foi aqui no Rio de Janeiro, o que facilitou a nossa presença.

<div>
<a href="http://www.pythonbrasil.org.br/" title="PythonBrasil[5]">
<img src="http://www.pythonbrasil.org.br/2009/saiba-mais/apoio-divulgue/pythonbrasil-rectangle.gif" alt="PythonBrasil[5]" />
</a>
</div>

Ruby e SQLite sem Rails

Estou desenvolvendo um programinha para consumir dados da API de buscas do Twitter e tive a ideia de implementar algum controle de usuário, para que a aplicação não faça muitas requisições ao Twitter e para que eles não me bloqueiem :-) .

Então resolvi utilizar o SQLite diretamente de um script feito em Ruby. Basicamente, nesse script eu preciso criar o banco de dados, a tabela com os campos, inserir dados e verificar se eles já foram inseridos anteriormente. Veja abaixo como poderia ser.

require 'sqlite'
 
#criando ou utilizando o banco de dados
db = SQLite::Database.new('example01.db', 0644)
 
#criando a tabela
db.execute_batch <<-SQL
      CREATE TABLE users (
          idx INTEGER PRIMARY KEY,
          username VARCHAR(255)
      );
SQL
 
#inserindo um dado no banco
db.execute( "INSERT INTO users (username) VALUES ('username01')" )
 
#fazendo uma consulta e verificando se já existe no banco
if db.execute("SELECT * FROM users WHERE username = '%s' " % "username01") != [] 
  puts "O usuario username01 já foi adicionado anteriormente no banco de dados."
end

Se você quiser aprender mais, dê uma olhada na documentação do plugin SQLite Ruby. Este post também explica uma série de macetes se você quiser aumentar a interação com o banco de dados.

FISL 10 – Terceiro dia

fisl10banner

Talvez vocês estranhem um post sobre o Terceiro dia de FISL sem um antecessor comentando o segundo, mas infelizmente este dia não merece maiores explanações. Improdutivo, palestras ruins e que não agregaram valor (pelo menos as que eu escolhi assistir).

Diferentemente do dia anterior, o Terceiro dia foi totalmente interessante. Pela manhã acompanhei uma palestra que comparava vários frameworks em PHP, como o Code Igniter, Cake PHP, Symfony e Zend. Quatro palestrantes apontavam tópicos que denotavam pontos positivos de seu framework predileto. Foi legal conhecer um pouco mais de frameworks PHP e o que eles estão oferecendo para aumentar a produtividade dos desenvolvedores.

Após essa palestra, assisti um grande resumo do que se propõe o Middleware Ginga, framework para ser utilizado em set-top-boxes de sistema de tv digital. O palestrante falou tanto do Ginga-J quanto o Ginga-NCL e sobre o que cada um poderia oferecer. Fica a dica para os que tem interesse em apostar na tecnologia.

Depois do almoço assisti pela primeira vez uma palestra do Fábio Akita e gostei muito do que ele preparou. Falou das possibilidades do Rails e mostrou o exemplo do blog de 15 minutos do David Heinemeier Hansson com outras funcionalidades incluídas e que agregaram muito valor (will_paginate, cucumber, rspec, cache entre outras). Acho que ele conseguiu mostrar, para quem ainda tem dúvidas em estudar Rails, que o framework consegue ser muito útil e produtivo.

Em seguida assisti a palestra do Mergulhão sobre um case muito interessante de escalabilidade em aplicações feitas em Rails. Ele, que trabalha no Rede Parede, demonstrou que é possível sim ter aplicações Rails para aguentar situações de grande estresse. Ele também demonstrou como sua aplicação foi crescendo, e como eles se planejaram para aumentar sua infraestrutura. Ficou evidente que quanto mais o Google indexava o site, mais o site crescia e eles puderam criar algumas testes sobre o Google.

Por último, assisti um palestrante que possui uma “empresa livre“, com todos seus serviços orientados para utilização de software livre. E sim, diferente do que pensam, é possível ganhar dinheiro com software livre (eu já sabia :D ).

Também não irei comentar sobre o quarto dia, pois depois que o Lula lá passou no evento, bagunçou todos os horários e prejudicou o andamento do evento. Que o ano que vem nenhum presidente pense em passar por lá.