quarta-feira, 30 de junho de 2010

Doctrine - Operações em lote ou "batch updates" - algums dicas

O Doctrine não é uma ferramenta feita para operações em lote, ele é um ORM. Mas tem alguns momentos que já temos o método na nossa camada de negócio e queremos chama-lo um monte de vezes para executar alguma manutenção no banco de dados ou algo assim.

Nestes momentos nem sempre é necessário reescrever tudo em um sql otimizado, em casos mais simples ou não tão críticos, podemos usar o que já temos. Porém, fazer esse tipo de operação no Doctrine requer alguns cuidados que temos aprendido com o tempo. Coloco aqui algumas dicas para quem quiser pular a fase do aprendizado pelo erro. Mais abaixo também coloco um exemplo de código para o tão famigerado e entretanto tão usado copy and paste.

Dicas:

1 - Faça um looping iniciando e "commitando" a transação. Isso aumenta em muito a velocidade de insert/update no banco. A quantidade de registros atualizados a cada iteração vai ter que ser definida na tentativa e erro, mas quanto mais simples a operação, maior a quantidade de itens que podem ser incluidos. Vale perceber que mesmo que a transação funcione, se forem muitos itens, o resultado final pode ficar mais lento mesmo assim.

2 - Sempre chame o método free() passando o parâmetro true para seus objetos instanciados pelo doctrine para que ele libere a memória usada por aquele objeto. Eu chamo também um unset() logo em seguida.

3 - Se você usar uma action no symfony (isso é, se é que você usa o symfony), ele tem uma mania de querer repetir a operação depois que termina. Por algum motivo que ainda não descobri, ele faz um redirect ou forward para a mesma action, então eu coloco aquele die() no final. Sei que ideal seria uma task rodando do shell, mas faço assim pq acho mais simples, principalmente para operações que vão rodar uma vez só. Se for algo que vai ser ativado pelo cron, aí não tem como fugir das tasks.

Para recortar e colar (divirta-se):


function executeRecalculateAllRatings() {
set_time_limit(3600);
$min = 0;
$increment = 1000;
$last = 50000;
$count = 0;
while ($min <= $last) { echo "<>NEW TRANSACTION - $min <>";
Doctrine_Manager::connection()->beginTransaction();
$comments = CommentTable::build()->findByIdRange($min, $min + $increment);
foreach($comments as $comment) {
$res = RatingLogTable::build()->calculateCommentRatingTotal($comment['id']);
$comment->setRating($res[0],$res[1]);
$comment->save();
$comment->free(true);
unset($comment);
echo $count++ . ' - ';
}
$min = $min + $increment;
Doctrine_Manager::connection()->commit();
}
die();
}

quarta-feira, 23 de junho de 2010

Git Submodules - um recurso para gerenciar dependências no lugar de svn externals.

Submodules & GIT - usando bibliotecas externas.

Quem está acostumado em gerenciar suas bibliotecas em svn usando o recurso externals, quando considera usar o GIT, geralmente tem dúvida a respeito de como trabalhar. Já escrevi aqui um artivo a respeito de svn externals e agora que estou migrando pro git então escrevo este aqui também para quem quiser me acompanhar.

Dois recursos normalmente surgem quando pesquisamos a respeito do assunto:
  • submodules
  • subtree merge strategy
Vamos tratar aqui do primeiro, porém quem quiser pesquisar o segundo, veja a comparação entre submodules e subtree merge strategy na documentação.

O que são submodules?

Na documentação diz que submodules ou submódulos permitem repositórios externos serem adicionados dentro de um subdiretório dedicado da arvore do nosso projeto, sempre apontando para um commit específico.

Bom... uma parte de cada vez:

repositórios externos
são outros repositórios em git.

diretórios dedicado
o diretório onde o submódulo fica tem sua arvore específica, inclusive a pasta .git com suas próprias configurações. Não pode ser feito merge com a arvore do repositório pai.

commit específico
quando adicionamos um submódulo a uma arvore, estamos adicionando um commit específico. Isso quer dizer que atrelamos ele a uma versão (um SHA). Toda vez que alguém baixar este projeto e pedir o submódulo ele vai receber esta versão mesmo que o repositório original esteja bem mais adiantado.

Isso é legal. Quero um pra mim. Como eu faço para criar um submódulo?

você deve usar um comando semelhante à este aqui (nessa hora o melhor mesmo é consultar o manual do git):

git submodule add [URL do repositório] [pasta de destino]
git submodule add http://github.com/brunoreis/pspec.git extlibs/pspec


com isso ele vai criar um repositório para o pspec na pasta extlibs/pspec. Vale a pena dar uma olhada nesta pasta, dentro do diretório .git, e ver o que tem nos arquivos texto de configuração. Com certeza vai auxiliar a encaixar as peças do quebra-cabeças. Ah, e também olhe o .git da raiz do seu projeto.

Bom, então é só isso? Meu submódulo está criado, posso mandar meu projeto para o github e ficar famoso porque uso submódulos e o pspec para especificar e testar meu software?

Muita hora nessa calma! Ainda temos algumas coisas a fazer antes. Ao criar o submodule, como já dissemos antes, atrelamos ele a um SHA específico. Os arquivos do repositório, a princípio, não ficam dentro do nosso repositório, mas o SHA sim. Temos então que adicionar o subdiretório criado à arvore original para que ele possa ser integrado ao nosso repositório.

Fazemos assim:
git add extlibs/pspec
git commig -m "agora sim com pspec"

Agora está lá... e se quiser subir para o repo de origem, não esqueça de fazer um push.

Isso quer dizer que quem fizer checkout no meu projeto já vai baixar o submódulo?

Não. Como já falei antes, você mandou apenas o SHA. Assim quando você fizer checkout vai trazer apenas uma referência à aquele submodulo, sem baixar o conteúdo do mesmo. Então após fazer checkout do seu repo, você ainda vai ter que fazer o seguinte:
git submodules init
git submodules update

Com isso ele vai trazer o conteúdo do(s) submódulos de acordo com o SHA de cada um.

E como eu faço pra saber se um projeto que baixei tem submódulos?

essa é fácil, é só rodar
git submodules

ele mostra os submódulos e também o SHA de cada um.

Beleza, mas agora eu sei que tem algo novo que eu preciso em um submódulo, como eu atualizo ele?

Simples, como o submódulo tem lá sua arvore e seu .git, etc.. porém este repositório está atrelado a um commit (sha) específico. Então precisamos fazer um checkout do branch que você quer, ex:

git checkout master

depois disso você pode usar

git pull

para atualizar.

Ah, e lembre-se de que depois que você fez isso, você tem que adicionar novamente o submodule ao repositório e fazer um commit (da atualização do SHA) para que os outros possam ter essa atualização.

Ao fazer essa atualização não coloque uma barra depois do nome do submodule. Se você fizer isso vai bagunçar tudo. Ou seja, use:
submodule add extlibs/pspec


mas NÃO USE

submodule add extlibs/pspec/ <--------------- Essa barra faz @#$@%@!!


Ta bom, ta bom....Hum.... e....

Se eu quiser atualizar todos de uma vez?

É só fazer assim:

git submodule foreach "git pull"

Esse comando eu achei muito interessante. Ele roda por todos os submódulos e executa o comando que for passado para ele, no noso caso o pull. Não esqueça de mandar esta alteração adicionando os submodules novamente à arvore principal.

Beleza, mas agora que estou no meu projeto, vi que tem um bug no repositório do submódulo. Tem como eu arrumar isso sem fazer checkout do sub em outro diretório?

Sim. Você pode entrar no dir do submódulo, fazer um checkout, alterar, fazer um commit e mandar novamente para o repo original.

Se você fizer isso e encontrar um erro dizendo que o original não aceita commits deste, leia este post a respeito do uso de "bare repositories".

Ta Bom.

Espero que você tenha sucesso usando os submódulos. Eles me parecem bem mais simples e dinâmicos que os externals do svn. Ainda estou aprendendo o git, então deve ter algo aqui que pode ser feito de uma maneira melhor ou então algo que você não entendeu. Peço que você acrescente seu comentário que se eu puder, respondo. Assim agregamos mais informações para os próximos não terem que ficar pesquisando as mesmas coisas que nós.

Sucesso!

--------------
Ah...

Algumas referências citadas e usadas aqui:

http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html

http://book.git-scm.com/5_submodules.html

https://git.wiki.kernel.org/index.php/GitSubmoduleTutorial

http://stackoverflow.com/questions/804545/what-is-this-git-warning-message-when-pushing-changes-to-a-remote-repository

sexta-feira, 18 de junho de 2010

PHP - Para fazer refactoring faz diferença se um método é públicos ou privados?

Para muitos o fato de um atributo ou método ser público ou privado pode nada ter a ver com refactoring de código. Afinal de contas isso tem mais a ver com o fato dessa classe poder ser acessada de fora ou não do objeto em questão. Então, a princípio, é melhor deixar aquele método público (padrão do php), afinal de contas deixando ele público, ele poderá ser usado por muitas outras classes, correto?

ERRADO!

Toda vez que você cria um método e declara ele como sendo público você está aumentando a interface do seu objeto. Com isso o seu sistema fica mais complexo.

E o que isso tem a ver com refactoring?

Para quem refatora código normalmente (todos fazem isso, correto? ), isso é bem fácil de entender. Se eu tenho um método público, estou dizendo que este método pode estar sendo chamado de qualquer lugar no sistema. Ou seja, se eu precisar alterar o meu método, vou precisar revisar o sistema inteiro para saber se alguém usa aquele método. E para uma linguagem dinâmica como o php, isso não é nenhum pouco fácil de fazer usando uma IDE.

Tudo que é dificil de fazer parece que atrai aquela conhecida de muitos programadores: preguiça! E a preguiça gera "ctrl+c ctrl+v". Resultado: código duplicado, dificuldade de fazer refactoring, problemas na implementação de novas regras. Mais erros, mais custo de manutenção, etc... Você deve conhecer esta novela!

Já se a pessoa que declarou o método colocou uma simples palavra antes dele (protected ou private), aí fica bem mais fácil de saber se o método está sendo usado no sistema, afinal de contas ele só poderá ser usado naquela classe ou filhas. Assim a preguiça fica no canto dela, o método é refatorado e o código fica limpo, fácil de mover, etc... espero que conheça esta história também! Se não conhece, a hora é agora. Sucesso!