desenvolvimento, python

Python Mixins

Um Mixin é um tipo especial de herança múltipla. Há duas situações principais onde são usadas:

1 – Deseja-se prover muitas características opcionais a uma classe.
2 – Deseja-se utilizar uma característica particular em várias classes diferentes.

Exemplo:

class Story(object):
    def __init__(self, name, content):
        self.name = name
        self.content = content

class StoryHTMLMixin(object):
    def render(self):
        return (
            "<html><title>%s</title><body>%s</body></html>" %
            (self.name, self.content))

class StoryHTML(Story, StoryHTMLMixin):
    pass

print StoryHTML(u'TÍTULO', u'CONTEÚDO').render()

A classe Story guarda atributos, enquanto a classe StoryHTMLMixin “decora” atributos com marcações de HTML. Veja que a classe mixin NÃO define os atributos que ela decora: ela espera que eles tenham sido definidos em outra classe (e eles foram, na Story!). A classe mixin sozinha não parece fazer sentido. Se for criado um objeto a partir dela e invocar o método render, será gerado um erro.

Finalmente é definida StoryHTML que utiliza de herança múltipla, e acaba por agregar/compor os atributos de Story com o método render de StoryHTMLMixin.

Neste exemplo, pelo fato da classe mixin usar os atributos name e content, há forte dependência com Story. Então o mixin está criando mais uma camada de complexidade que poderia ser evitada usando herança simples (StoryHTML poderia herdar de Story e compor seus atributos com as marcações).

Mas se houver uma família de classes que segue um padrão na hora de nomear seus atributos (classes A, B, C, D, E, F e G possuem os atributos name e content), então uma mesma classe StoryHTMLMixin poderia ser agregada com qualquer uma dessas classes.

Mixins em geral não implementam um método __init__, porque sua principal razão de existir é contribuir com métodos para outras classes, e os objetos são fundamentalmente criados e inicializados por estas outras classes.

Referências:

http://stackoverflow.com/questions/533631/what-is-a-mixin-and-why-are-they-useful
http://stackoverflow.com/questions/4514803/diamond-problem-when-using-mixins-in-python
http://turing.com.br/wiki/index.php?title=Objetos_Pythonicos

desenvolvimento, linux, python

Ambientes virtuais para Python no Ubuntu

Preparando o ambiente:

sudo apt-get install python-pip
sudo apt-get install python-virtualenv
sudo apt-get install virtualenvwrapper

Adicione o controle de cache para baixar os pacotes do pip apenas uma vez:

echo 'export PIP_DOWNLOAD_CACHE=$HOME/.pip_download_cache' >> $HOME/.bashrc 

Para criar uma máquina virtual para o projeto MEU_PROJETO sem acesso aos pacotes do sistema:

mkvirtualenv -p /usr/bin/python2 MEU_PROJETO

Para criar uma máquina virtual para o projeto MEU_PROJETO com acesso aos pacotes do sistema:

mkvirtualenv -p /usr/bin/python2 MEU_PROJETO --system-site-packages

Para começar a trabalhar nesta vm, basta entrar com o comando:

workon MEU_PROJETO

Agora, todas as modificações ou instalações de pacotes ocorrem apenas para esta vm, sem interferir nas demais, ou no ambiente do host.

ATENÇÃO:
O switch para esta vm ocorreu apenas neste terminal aberto.
Se você trabalhar em múltiplos terminais (num deles você entrou no shell do python, noutro você carregou um servidor web) terá que ter executado o comando workon em cada terminal.

Instalando o Django 1.4, por exemplo:

Verifique que não temos o django ainda na nossa nova vm:

pip freeze

Agora instalamos o pacote. É preferível especificar a versão que queremos, caso contrário ele irá baixar a versão mais recente. Se quiséssemos sempre as últimas versões, não precisaríamos virtualizar ambientes.

pip install django==1.4

Verifique novamente o pip freeze. Agora ele contempla o django 1.4

Para sair de uma vm e voltar para o host:

deactivate

Agora os pacotes exibidos pelo pip freeze serão referente ao host, e não à nossa vm.

Um pacote que não controlamos pelo pip em uma vm é o próprio python.
Se você desejar usar o python 3, por exemplo, ele deve ser definido na criação da vm (no comando mkvirtualenv).

Para saber que opções de python você tem verifique com:

ls /usr/bin/python*

Para criar ambientes virtuais com alguns pacotes sendo instalados na geração:

gedit $HOME/.virtualenvs/postmkvirtualenv

Adicione no arquivo N comandos de instalação: “pip install PACOTE”

desenvolvimento, java

Double Buffer em Java

Sobrescrever o método update do componente que irá renderizar a imagem. Do contrário ele sempre irá chamar o método clearRect herdado de Container, que irá produzir o efeito de “flick” ao limpar a tela.

@Override
public void update(Graphics g) {
    paint(g); // não limpa a tela: apenas rechama o método paint
}

Desenhar no objeto graphics de uma imagem offscreen tudo que será renderizado. Só então copiar esta imagem pronta para a saída padrão do componente:

@Override
public void paint(Graphics g) {
    Image offscreen = createImage(width, height); 
    Graphics backBuffer = offscreen.getGraphics(); 
        
    backBuffer.clearRect(0, 0, width, height); 

    // desenhos feitos por este método
    backBuffer.drawString...
    backBuffer.drawRect...
    backBuffer.drawOval...
    backBuffer.drawLine...
    backBuffer.drawImage...

    // desenhos feitos por objetos complementares
    meuObjeto.paint(backBuffer);

    // copia todo o desenho para a tela
    g.drawImage(offscreen, 0, 0, this);
}

Quando quiser atualizar a tela, basta chamar repaint normalmente.

aplicacoes, cpp, desenvolvimento, linux

Ubuntu, Eclipse C++, Valgrind

Instalar Eclipse IDE for C/C++ Linux Developers:
http://www.eclipse.org/downloads/

Baixar Valgrid:

sudo apt-get install valgrind

Para gerar o profiling do projeto no Eclipse, acesse o menu RUN / PROFILE / Profile with Valgrind.

O resultado da análise é mostrado na view Valgrind.

Lembrando que apenas o que for chamado direta ou indiretamente pelo método main será analisado.

Para analise de um binário via linha de comando execute:

valgrind PATH_DO_EXECUTAVEL

Após finalizar o uso, será exibido no terminal o resultado do profiling do binário.

desenvolvimento, padroes, tests

TDD: Rodar testes ANTES de implementá-los

A idéia básica da programação orientada a testes segue a seguinte estrutura:

1. Escreva um novo teste que faça asserção num método de produção (existente ou não)
2. Implemente em produção APENAS a estrutura mínima para que o teste seja compilável, ou seja, crie o método “crú” se ele não existir ainda
3. Compile e rode os testes
4. Se os testes passarem, volte para o passo 1, senão altere o código e volte para o passo 3

Pode parecer estranho o passo 3 mandar que se rode os testes sabendo que definitivamente ele não vai passar na primeira vez que um método de produção for criado. Afinal no passo 2 a estrutura mínima era basicamente a implementação da assinatura do método, com eventuais retornos dummies (return 0 ou return null).

Então por que é tão importante forçar um erro no teste tão prematuramente? Por que não tentar programar alguma funcionalidade mínima para então rodar o primeiro teste?

Para deixar a barrinha vermelha o quanto antes!!!

Um novo teste não concluído pode ser esquecido enquanto temos uma barrinha verde dando a falsa impressão de que o estado atual do desenvolvimento não tem problemas.

O teste esquecido e a barrinha verde conduzem a conclusão do trabalho (liberar código quebrado para revisão, começar a trabalhar em outro bug, etc…).

O feedback de testes sempre deve ser: “há algum teste que foi considerado, mas que o sistema ainda não trata”.

Esse tipo de postura no TDD é chamada de Programação por Intenção: chama-cria-verifica-corrige.

Referência:
http://improveit.com.br/xp/praticas/tdd

db, desenvolvimento, java, padroes

Java Acesso a Banco

Baixe o driver JDBC para o java acessar o banco.

Postgres:
http://jdbc.postgresql.org/download.html

MySQL:
http://www.mysql.com/downloads/connector/j/

Firebird:
http://www.firebirdsql.org/en/jdbc-driver/

Aplicações desktop, sem conceito de multi-usuário:

– Acrescente o jar do JDBC no buildpath do eclipse (o eclipse ignora o classpath do sistema!!)

– Para descobrir o nome completo da classe de driver, abra o jar do JDBC e encontre a classe correta (sem o .class).
Postgres: org.postgresql.Driver
MySQL: com.mysql.jdbc.Driver
Firebird: org.firebirdsql.jdbc.FBDriver

– Cada banco tem uma identificação como: postgresql, mysql, oracle, sqlserver, firebirdsql, etc…

String driver = "NOME_DA_CLASSE_DE_DRIVER";
String server = "IDENTIFICACAO_DO_BANCO";
String host = "IP_SERVIDOR_DO_BANCO";
String port = "PORTA_DO_SERVIDOR_DO_BANCO";
String database = "NOME_DO_BANCO";
String user = "NOME_DO_USUARIO";
String passwd = "SENHA_DO_USUARIO";
String query = "QUERY";

Class.forName(driver);
Connection con = DriverManager.getConnection("jdbc:" + server + "://" + host + ":" + port + "/" + database, user, passwd);
PreparedStatement pstmt = con.prepareStatement(query);
ResultSet rs = pstmt.executeQuery();

Aplicações distribuídas:

– Copie a jar do JDBC na pasta WebContent/WEB-INF/lib

Também é válido copiar bibliotecas para $CATALINA_HOME/lib.

Porém isso conduz a problemas de jar-hell se houverem multiplas aplicações no tomcat com diferentes versões da mesma biblioteca.

Há ainda transtorno para novos desenvolvedores e/ou novas máquinas de produção: vão precisar jogar em seus próprios servidores uma cópia dessas bibliotecas.

Melhor se cada deploy for o mais completo possível, carregando suas próprias dependências.

– Defina os parâmetros de gerência de conexões que o pool deverá seguir em context.xml. Este arquivo deverá estar localizado em Web-Content/META-INF.

<?xml version="1.0"?>

<Context docBase="NOME_DO_PROJETO" path="/PATH_RELATIVO_DO_PROJETO">

	<Resource name="NOME_DO_DATASOURCE" auth="Container"
		type="javax.sql.DataSource" maxActive="50" maxIdle="5" maxWait="500"
		username="NOME_DO_USUARIO_DO_BANCO" password="SENHA_DO_USUARIO_DO_BANCO"
                driverClassName="NOME_DA_CLASSE_DE_DRIVER"
		url="jdbc:IDENTIFICACAO_DO_BANCO://IP_SERVIDOR_DO_BANCO:PORTA_DO_SERVIDOR_DO_BANCO/NOME_DO_BANCO"/>
		
</Context>

– Adicione um ServiceLocator, que irá buscar a conexão de um pool gerenciado pelo servidor de aplicação:

package service;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ServiceLocator {
	
	private ServiceLocator() {		
	}
	
	public static Connection getConnection(String dataSouce) throws NamingException, SQLException, NullPointerException {
		Connection result = null;
		InitialContext initialContext;
		Context context;
		DataSource dataSource;
			
		initialContext = new InitialContext();
		context = (Context) initialContext.lookup("java:comp/env");
		dataSource = (DataSource) context.lookup(dataSouce);
		result = dataSource.getConnection();
			
		if (result == null) {
			throw new NullPointerException("Conexão nula para: " + dataSouce);
		}
		return result;
	}

}

Diferente da versão desktop, não é responsabilidade dos objetos de acesso a dados invocarem Class.forName(driver);.

O servidor de aplicação é quem fará isso automaticamente quando estiver no ar.

A obtenção do objeto de conexão ficará assim:

Connection con = ServiceLocator.getConnection("NOME_DO_DATASOURCE");