tag:blogger.com,1999:blog-62052183212091835422023-11-16T03:11:24.194-08:00Hugo's BlogGeeknessHugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.comBlogger11125tag:blogger.com,1999:blog-6205218321209183542.post-73195443287397182892012-02-22T13:25:00.004-08:002012-02-22T13:45:09.019-08:00Mudando o blog para blog.hltbra.net<span style="font-style: normal; ">Depois de ler o livro </span><i>The Elements of Style</i> eu decidi começar a blogar em inglês, e agora eu estou com um blog usando <a href="http://jekyllrb.com">Jekyll</a> + <a href="http://disqus.com">Disqus</a> + Amazon S3 + Amazon EC2 em <a href="http://blog.hltbra.net">blog.hltbra.net</a>.<div><br /></div><div><a href="http://blog.hltbra.net/2012/02/22/the-practice-of-programming-thoughts.html">O primeiro post que eu escrevi foi sobre o livro The Practice of Programming.</a></div><div><br /></div><div>O novo feed é <a href="http://feeds.feedburner.com/hltbra">http://feeds.feedburner.com/hltbra</a>.</div><div><br /></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com0tag:blogger.com,1999:blog-6205218321209183542.post-74299012766185018582011-08-22T19:53:00.000-07:002011-08-22T19:53:49.201-07:00Meu Começo: Linguagem C<br />
Acabaram de me pedir "orientações", e eu comecei a me lembrar do que eu estudei quando estava começando a programar.<br />
<div class="document" id="meu-comeco-linguagem-c">
<br />
Resolvi colocar nesse post um resumo do meu início, e fazer algumas recomendações.<br />
<br />
Eu comecei a me interessar por computadores logo que ganhei o meu primeiro, quando eu tinha 10 anos, e o que eu mais gostava de fazer era ficar no mIRC nos fins-de-semana e madrugada. Até que um dia, o irmão de um amigo meu resolveu falar pra eu começar a aprender a programar, e me passou uma apostila de C da UFMG.<br />
<span class="Apple-style-span" style="font-size: large; font-weight: bold;"><br /></span><br />
<span class="Apple-style-span" style="font-size: large; font-weight: bold;">Primeira apostila: Apostila de C da UFMG</span><br />
<div class="section" id="primeira-apostila-apostila-de-c-da-ufmg">
<br />
Eu nem sabia o que era linguagem, e já fui estudando umas apostilas de lógica que eu achava na internet, e logo em seguida comecei a estudar a tal apostila de C da UFMG que o Vitor Padilha havia me recomendado. Eu tinha uns 12 anos, e não entendia muita coisa, aí brinquei uma ou duas semanas e desisti. Me senti um merda. Fiquei brincando com mIRC scripting até que com uns 13 pra 14 eu resolvi voltar a aprender a programar.<br />
<br />
Eu sempre usei IRC, e na época eu usava a BrasNet. Muitas pessoas do #C me ajudaram na época, inclusive pessoas de comunidades do Orkut, como o professor <a class="reference external" href="http://www.paulomotta.pro.br/">Paulo Motta</a>, que me ajudou muito no meu início, via MSN/Gtalk.<br />
<br />
Eu fiquei nessa de aprender por mais de um ano, e nesse meio tempo muita coisa, tudo pelas dicas da galera da BrasNet.<br />
<br />
A apostila de C da UFMG sempre foi uma lenda, e muitas pessoas a recomendam até hoje! Depois de estudar muito C, vi que ela é legal para dar uma passada superficial pela linguagem, mas não é tão legal pra ter como referência.<br />
<br />
Eu não a recomendaria hoje em dia.<br />
<br /></div>
<br />
<div class="section" id="primeiro-livro-c-completo-e-total">
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: large;">Primeiro livro: C Completo e Total</span></span><br />
<br />
O Paulo falava muito sobre esse livro, e eu decidi baixar e começar a lê-lo no computador. O livro é uma bíblia, tem umas 800 páginas!<br />Tem muita coisa interessante no livro que não está totalmente ligado a linguagem C - no início eu me lembro de explicações sobre stack, heap e etc, que achei muito legal, pois eu não havia lido isso em lugar nenhum. Acho que foi fundamental eu ter gasto meses nesse livro, e com certeza aprendi muito com ele.<br />
<br />
Um ponto fraco do livro é que tem muitos exemplos de coisas que só funcionam com bibliotecas da Borland no sistema, e algumas péssimas práticas.<br />
<br />
É um livro razoável pra ter como referência.<br />
<br /></div>
<br />
<div class="section" id="o-melhor-the-c-programming-language-2nd-edition">
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: large;">O melhor: The C Programming Language, 2nd edition</span></span><br />
<br />
O livro é muito foda. É o melhor material sobre C (c89/k&r) que eu já li até hoje. O livro é bem pequeno, mas é fantástico. Os autores são: Dennis Ritchie e Brian Kernighan, duas lendas, e ambos autores do UNIX.<br />É uma ótima leitura, recomendo a todos que querem aprender C, lê-lo. Ele é conhecido como K&R2.<br />
<br />
Há poucos dias o Zed Shaw fez umas críticas a esse livro no twitter, falando sobre algumas má praticas usadas em exemplos do livro.<br />Eu concordo com o Shaw em alguns pontos, mas os exemplos são muito sucintos e adequados, e isso facilita muito pra quem está aprendendo.<br />
<br />
É claro que há muita coisa de C que só é possível aprender lendo código e conversando com pessoas. Por isso eu recomendo frequentar o canal ##c na Freenode, pra quem está aprendendo C. Já obtive muita ajuda lá também (depois que eu parei de usar a BrasNet).<br />
<br /></div>
<br />
<div class="section" id="muitas-man-pages">
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: large;">Muitas Man Pages</span></span><br />
<br />
Essa semana eu estava conversando no almoço com alguns amigos da Globo.com sobre documentação de linguagens, e eu falei sobre o meu início, em que eu tinha um Slackware numa máquina virtual,<br />e usava internet discada, e logo, tudo o que eu tinha pra estudar C eram as man pages.<br />
<br />
São documentações EXCELENTES. Segundo o <a class="reference external" href="http://twitter.com/everton_carpes">Everton Carpes</a>, o motivo disso é a maturidade, já que a GLIBC tem uns 30 anos.<br />
<br />
Recomendo muito que todos aprendam a fazer consultas pelas man pages, antes de ir ao Google.<br />
<br />
Antes que eu me esqueça: leiam a man page do <cite>scanf</cite>, ele é muito mais poderoso do que os livros mostram.<br />
<br /></div>
<br />
<div class="section" id="lendo-codigo-dos-outros">
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: large;">Lendo código dos outros</span></span><br />
<br />
Como eu não poderia deixar de falar, ler código dos outros é uma das melhores maneiras de aprender uma linguagem nova.<br />
<br />
Um que me marcou foi o código do MINIX. Eu, obviamente não entendia nada de sistema operacionais, mas eu queria ver como programadores C de verdade escreviam código, e lá aprendi alguns padrões que eram usados na época, alguns truques com pré-processador e etc.<br />
<br />
Na época o host de projetos opensource mais famoso era o SourceForge, e de lá eu já baixei muito código pra ler, e me lembro de um ircbot que o Isaque Dutra estava escrevendo em C, eu comecei a hackear pra aprender como funcionava a comunicação pela rede, e era tão newbie que nem sabia usar o CVS (que era o SCM usado no SourceForge naquela época).<br />
<br /></div>
<br />
<div class="section" id="conclusao">
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: large;">Conclusão</span></span><br />
<br />
Acho que é fundamental que todo programador aprenda alguma linguagem que seja de mais baixo nível, como experiência de vida mesmo, porque é necessário aprender a escovar bits e se virar com os poucos recursos existentes.<br />
<br />
Apesar de ter estudado muito C, nunca escrevi nenhuma biblioteca/framework interessante em C,<br />mas sinto que criei uma base bem sólida pra evoluir desde então.<br />
<br /></div>
<br /></div>
<br />
<br />
<br />Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com6tag:blogger.com,1999:blog-6205218321209183542.post-4259877225040942112010-08-03T05:49:00.000-07:002010-08-03T05:52:26.167-07:00Sprint de Tradução do Python 3000 pra pt-BR<div class="document" id="sprint-de-tradu-o-do-python-3000-pra-pt-br"><p>Vendo alguns tweets acabei me deparando com o projeto do Robert Lehmann, que está desenvolvendo um mecanismo de i18n pra ser usado no <a class="reference external" href="http://sphinx.pocoo.org/">Sphinx</a>. A idéia é tornar possível sites como o <a class="reference external" href="http://docs.python.org/">http://docs.python.org</a> usarem os mesmos <tt class="docutils literal"><span class="pre">.rst</span></tt>, porém, com apoio de arquivos <tt class="docutils literal"><span class="pre">.po</span></tt>, pra gerar sites traduzidos.</p><p>Achei a idéia muito boa, afinal, muita gente tem necessidade de traduzir documentação gerada com o <a class="reference external" href="http://sphinx.pocoo.org/">Sphinx</a> pra diversas línguas. A idéia é que as traduções sejam simples de serem executadas. Assim, ele está usando um software de tradução colaborativa web, o <a class="reference external" href="http://translate.sourceforge.net/wiki/pootle/index">Pootle</a>.</p><p>Alguns dias depois de ver a notícia me veio a cabeça: Por que não tentar um sprint pra traduzir o máximo que nós pudermos pra pt-BR? Afinal, a comunidade de pythonistas brasileiras é muito grande!<br />Foi assim que eu envei uma chamada pra <a class="reference external" href="mailto:python-brasil@yahoogrupos.com.br">lista da PythonBrasil</a>, convidando todos a participarem de um sprint numa quarta-feira (14/07/2010), às 19h no canal #python-docs-br na Freenode.</p><p>Alguns amigos e ex-amigos de trabalho já estavam traduzindo algumas strings la na <a class="reference external" href="http://pootle.python.org/">instância do Pootle</a> que o Robert criou e foi fácil achar gente pra ajudar :-)</p><br /><div class="section" id="como-foi-o-sprint"><h1>Como foi o Sprint</h1><p>Eu não tinha muita idéia de como seria o sprint, mas eu tinha o que eu precisava: gente disposta a ajudar e que sabia inglês. O sprint foi totalmente colaborativo, e todo mundo se ajudou. O Robert ficou presente no canal do início ao fim - ele gostou muito da idéia do sprint.</p><p>Nós fomos os primeiros a usar massivamente o sistema, e vimos algumas coisas que dificultaram as traduções e que esperamos que nos próximos encontros não tenhamos os mesmos problemas.</p><p>Infelizmente, muita gente apareceu bem depois que nós já havíamos iniciado e algumas pessoas não puderam ficar no momento da tradução. Outro problema foi que acabou não dando tempo de revisar muita coisa, pois o Pootle dificultou um pouco achar os tópicos dentro do <tt class="docutils literal"><span class="pre">.po</span></tt>.</p></div><br /><div class="section" id="os-documentos"><h1>Os documentos</h1><p>Nós acabamos por usar uns sites que disponibilizavam documentos colaborativos. Tentamos o <a class="reference external" href="http://typewith.me/">Typewith.me</a> primeiro, mas ele não estava aguentando muita gente no mesmo documento. Optamos por usar o <a class="reference external" href="http://collabedit.com/">Collabedit.com</a>.</p><p>Para evitar que o documento seja alterado, disponibilizei-o aqui: <a class="reference external" href="http://gist.github.com/506293">http://gist.github.com/506293</a></p></div><br /><div class="section" id="participantes"><h1>Participantes</h1><p>Algumas pessoas estavam presentes mas acabaram não traduzindo nada no sprint, porém, muita gente tem traduzido esporadicamente um pouco lá no site.</p><p>Estavam no canal na hora do sprint e adicionaram seu nomes:</p><ul class="simple"><br /><li>Hugo Lopes Tavares (hugo_br)</li><li>Renato de Pontes Pereira (renatopp)</li><li>Diógenes Augusto Fernandes Hermínio (diofeher)</li><li>Hugo Henriques Maia Vieira (hugomaiavieira)</li><li>Gabriel Manhães Monnerat (gmonnerat)</li><li>Gabriel Lima de Oliveira (gabrieloliveira)</li><li>Herman da Rosa Caldara (herman)</li><li>André Ericson (ShexNivis)</li><li>Jonh Edson Ribeiro de Carvalho (jonhedson)</li><li>Daniel Gonçalves (spanazzi)</li><li>Osvaldo M Yasuda (omyasuda)</li><li>Robert Lehmann (stargaming)</li></ul></div><div class="section" id="o-p-oximo"><br /><h1>O Pŕoximo</h1><p>Ainda não marcamos, mas acabei de olhar meus e-mails e vi que a galera já está querendo outro!</p><p>E aí, vamos aproveitar e contribuir com nossa comunidade? :)</p><br /></div><br /></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com3tag:blogger.com,1999:blog-6205218321209183542.post-20421586560551632552010-07-11T08:28:00.000-07:002010-07-11T13:15:13.897-07:00Mini-sprint pra tradução da documentação do PythonDepois de ver os esforços de <a href="http://gsoc.robertlehmann.de/">Robert Lehmann</a> para criar um mecanismo de i18n pro Sphinx, de forma a tornar possível manter múltiplas traduções da <a href="http://docs.python.org/">documentação oficial do Python</a> eu decidi dar uma olhada no site e acabei traduzindo algumas strings.<div><br /></div><div>Bem, a primeira coisa que eu notei foi que o meu amigo <a href="http://hugomaiavieira.com/">Hugo Maia Vieira</a> já havia traduzido alguns arquivos e pareceu ter grandes interesses em traduzir a documentação.</div><div><br /></div><div>Entrei em contato com o Robert hoje, perguntando sobre o sitema que ele está criando e sobre quão estável está o <a href="http://pootle.python.org/">sistema de traduções</a>. Ele deixou bem claro que está totalmente em beta, mas que haveria possibilidades de criar traduções, e que era pra eu avisá-lo quando eu fosse alterar uma quantidade grande de arquivos, que ele iria tentar não fazer bagunça no sistema :)</div><div><br /></div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;"><b>A Idéia de um Mini-Sprint</b></span></div><div>Há pouco tempo o pessoal da Python Software Foundation começou a patrocinar sprints, começando com o Packaging Sprint, em Montréal. Dois caras do projeto distutils, também participantes do Google Summer of Code 2010, fizeram um mini-sprint há poucos dias, e parece que foi bem interessante.</div><div><br />Pois bem, eu tive a idéia de fazer um mini-sprint pra traduzir um pouco da documentação do Python 3, e ver que bicho dá.</div><div><br /></div><div>A comunidade brasileira de Python é imensa, e eu creio que essas traduções serão úteis a todos. Além disso, se conseguirmos realizar com sucesso o sprint, seremos pioneiros!</div><div><br /></div><div>Além do mais, é uma forma de ajudar o Robert com idéias de como facilitar a forma que as traduções são feitas.</div><div><br /></div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;"><b>Onde e Quando</b></span></div><div>Estou pensando em organizar o mini-sprint na quarta-feira (14/07/2010), começando às 19:00 e terminando no máximo 23:00, chat através do canal #python-docs-br, na rede Freenode.</div><div><br /></div><div>Os documentos que eu vejo como mais importantes são (não nessa ordem):</div><div><ul><li>tutorial</li><li>faq</li><li>library</li><li>howto</li><li>whatsnew</li><li>install</li><li>using</li><li>glossary</li><li>reference</li></ul><br /><div><span class="Apple-style-span" style="font-size: x-large;"><b>Como Participar</b></span></div></div><div>Basta aparecer no canal #python-docs-br na Freenode antes das 19:00, no dia 14/07/2010 e dizer que quer participar!</div><div><br /></div><div>Crie uma conta no <a href="http://pootle.python.org/pootle/pt/python/">http://pootle.python.org/</a> e comece a brincar um pouco pra ver como é o sistema, assim no Sprint teremos menos problemas.</div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com1tag:blogger.com,1999:blog-6205218321209183542.post-90411210368432262262010-06-13T06:59:00.000-07:002010-06-13T07:49:22.124-07:00My first 2 weeks in Google Summer of Code (May 24 - June 4)<div><span class="Apple-style-span" style="font-size: x-large; "><br /></span></div><div><span class="Apple-style-span" style="font-size: x-large; ">My Acceptance in Google Summer of Code</span></div><div><br /></div><div>My proposal has been sent to Python Software Foundation, to work on <a href="http://pip.openplans.org/">Pip</a>, and my abstract was:</div><div><span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px; border-collapse: collapse; ">"The goal is to make pip less error-prone, work well in python2.x and<br />python3.x, make the tests more internet-independent, run platform<br />independently, add needed features by developers, write more<br />documentation and make people love it and see that easy_install's age<br />has gone."</span><br /><br />I was very happy because my proposal was accepted and now I can work in a well known opensource project, with different people around the world working with me - this is a great oportunity Google, PSF and Pip guys are giving me and I will enjoy the most!</div><div><br /></div><div>So, I got my job started in May 24 and this post is about my first two weeks.</div><div><br /></div><div><br /><span class="Apple-style-span" style="font-size: x-large;">First Two Weeks: Cotinuous Integration Server</span><br /><div><br /></div><div>My first two weeks were about setting up a continuous integration server with builds for python2.4, python2.5 and python2.6, both in Ubuntu Server 9.10 and Windows 2008 Server. Ian Bicking gave me access to a server (in cloud) and I used Hudson CI Server to create the buids. Access it here: <a href="http://ci.cloudsilverlining.org/view/pip">http://ci.cloudsilverlining.org/view/pip</a></div><div><br /></div><div>I added some documentation while getting this work done and some other work, related to continuous integration, like some features requests in the Issue Tracker have been done too.</div><div><br /></div><div><br /></div></div><div><span class="Apple-style-span" style="font-size: x-large;">The Meetings</span></div><div><br /></div><div>My mentors <a href="http://twitter.com/carljm">Carl Meyer</a>, <a href="http://twitter.com/ianbicking">Ian Bicking</a> and <a href="http://twitter.com/jezdez">Jannis Leidel</a>, decided with me, to have weekly meetings in IRC, on Thursday, 10:00 PM (UTC), in #pip channel at Freenode. I am very lucky, because my mentors are really cool guys, are always helping me and the meetings are informal and I feel free to speak.</div><div>We had a meeting through Skype (me, Carl and Ian) and I started it a bit nervous, because it had too long I do not talk only in english to people, but they understood my intentions and the meeting was quick and focused.</div><div><br /></div><div>The second meeting was with all of them, but just through IRC and it took a bit longer, but we discussed more stuff and for what I realized, I was doing a good job.</div><div><br /></div><div><br /></div><span class="Apple-style-span" style="font-size: x-large; ">The Lesson</span><br /><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;"></span>I got a lesson from this all: learn by yourself, don't depend on your college/school, learn english as soon as possible and help the community.</div><div><br />I started programming when I was 14. It had a good time learning C and algorithms and getting help through IRC. When I was 16 I started working in a <a href="http://nsi.iff.edu.br/">research group</a>, in my <a href="http://iff.edu.br/">school</a>, and I was the youngest guy and I have learned too much there and I knew great people. I learned Python, Agile methods, top technologies and other things with them, and I was still in high school. Now I am in my first college year, 18 years old and I realize that I am lucky, because I thoroughly enjoyed the opportunities I had. And if I've not took english classes when I was younger, I could not have learned what I learnt about computing, software and all around these.<br /><br /><br />In PyConBrasil 2008 I asked an advice to Bruce Eckel, and his advice was basically: "Do something for the community". And I am doing it since that!<br /><br />So, my advice to people are starting now: learn english, study by yourself and meet great people!<br /><br />Thank you all guys, for helping me along my journey!<br /></div><div><span class="Apple-style-span" style="font-size: large;"><br /></span></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com1tag:blogger.com,1999:blog-6205218321209183542.post-576409774188110742010-05-26T18:34:00.001-07:002011-03-07T05:28:58.088-08:00Prompt colorido e com git branch<p>Meu terminal (gnome-terminal + bash) está assim no meu Ubuntu 9.10:</p><br /><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh94xvnLaU99rtrVEByvkfFUSC4ZmpDyRRweqLMnPYJ8t4N14c-Gh-MOFO5iDwrQf0RSZjdpzaV4SW3_682apOX5WuycvT1WRoi8HWTqNDFLx31yGSG60-mac4XPuLPMQoP2cweQjXddJc/s1600/terminal_colorido.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 247px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh94xvnLaU99rtrVEByvkfFUSC4ZmpDyRRweqLMnPYJ8t4N14c-Gh-MOFO5iDwrQf0RSZjdpzaV4SW3_682apOX5WuycvT1WRoi8HWTqNDFLx31yGSG60-mac4XPuLPMQoP2cweQjXddJc/s400/terminal_colorido.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5475764010710052946" /></a><br /></div><br /><br /><p>Eu alterei a fonte para Monaco 12px, troquei as cores e adicionei ao prompt o branch do repositório que eu estou (caso a pasta seja um repositório git).</p><p>E como isso foi feito?</p><p><br /></p><br /><br /><h2>Instalando a Fonte Monaco no Ubuntu</h2><br /><br /><p>A instalação da fonte Monaco no Ubuntu pode ser feita da seguinte maneira:</p><br /><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">sudo mkdir /usr/share/fonts/macfonts<br />sudo wget http://jorrel.googlepages.com/Monaco_Linux.ttf -O /usr/share/fonts/macfonts/Monaco_Linux.ttf<br />sudo fc-cache -f -v<br /></pre><br /><br /><p>O diretório <code>/usr/share/fonts/macfonts</code> será criado, a fonte <code>Monaco_Linux.ttf</code> será colocada em tal diretório e as configurações de fontes do sistema serão atualizadas. Muito simples!</p><br /><p>(Créditos do post <a href="http://jorrel.blogspot.com/2007/11/monaco-on-ubuntu.html">http://jorrel.blogspot.com/2007/11/monaco-on-ubuntu.html</a>)</p><br /><br /><h2>Como Adicionar o git branch ao Prompt</h2><br /><p>No terminal há uma variável de ambiente chamada <code>PS1</code>, ela guarda a mensagem que será apresentada ao usuário do terminal. Imagine a seguinte situação:</p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">hugo@hugo-laptop:~$ echo $PS1<br />\u@\h:\w$<br /></pre><br /><p>Isso significa que será mostrado na mensagem o usuário do sistema, um arroba, o hostname, dois pontos, o diretório atual e um cifrão. Em outras palavras, significa dizer que o usuário é identificado por <strong>\u</strong>, enquanto o hostname é <strong>\h</strong> e o diretório é <strong>\w</strong>.</p><br /><p>Para personalizar as mensagens é simples, basta alterar o valor da variável PS1! Por exemplo:</p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">hugo@hugo-laptop:~$ pwd<br />/home/hugo<br />hugo@hugo-laptop:~$ export PS1="prompt do \u:\w$ "<br />prompt do hugo:~$ pwd<br />/home/hugo<br />prompt do hugo:~$<br /></pre><br /><br /><p>A idéia é adicionar à mensagem o nome do branch do repositório git. Para saber o nome do branch no git basta um `git branch` e olhar a linha que começa com asterisco. Por exemplo:</p><br /><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">hugo@hugo-laptop:~/should-dsl$ git branch<br />master<br />* matchers-as-functions<br />new_matchers_based_on_hamcrest<br />nsigustavo_master<br />rodrigomanhes<br />separate-matchers<br />hugo@hugo-laptop:~/should-dsl$<br /></pre><br /><br /><p>Se for desejado saber apenas o branch atual, podemos usar o grep pra fazer isso:<br /></p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">hugo@hugo-laptop:~/should-dsl$ git branch | grep ^\*<br />* matchers-as-functions<br />hugo@hugo-laptop:~/should-dsl$<br /></pre><br /><br /><p>E se quisermos apenas o nome do branch, sem o asterisco, podemos usar o sed pra remove-lo:</p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">hugo@hugo-laptop:~/should-dsl$ git branch | grep ^\* | sed 's/\* //'<br />matchers-as-functions<br />hugo@hugo-laptop:~/should-dsl$<br /></pre><br /><p>Agora já podemos adicionar o nosso branch à mensagem do terminal:</p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">hugo@hugo-laptop:~/should-dsl$ branch=`git branch 2>/dev/null| grep ^\* | sed 's/\* //'`<br />hugo@hugo-laptop:~/should-dsl$ export PS1="\u@\h:\w($branch)$ "<br />hugo@hugo-laptop:~/should-dsl(matchers-as-functions)$<br /></pre><br /><p>O redirecionamento de erros é pra tratar o caso do comando `git branch` dar um erro, ou seja, a pasta atual não ser um repositório git.</p><br /><br /><p>Mas o interessante é ter cores, não!?</p><br /><br /><h2>Cores no Terminal</h2><br /><p>É possível usar cores nos terminais unix através de algumas sequências ASCII de cores. Há uma biblioteca, <a href="http://pypi.python.org/pypi/termcolor">termcolor</a>, que traz esse recurso pro python. Assim, é possível usá-la pra colorir o terminal. Mas no nosso caso vamos ser mais hardcores e lidarmos com as nossas sequências manualmente (porque queremos ser independentes!).</p><br /><br /><p>O padrão das sequências de cores é basicamente o seguinte: uma sequência dizendo que se inicia a sequencia, um modificador opcional, a cor, o texto e o finalizador de cor. O que eu quero dizer por modificador é um negrito, por exemplo.</p><br /><br /><p>A cor verde, por exemplo, é identificada pelo número 32. A sequência de cores se inicia sempre com um <b>\033[</b> e sempre termina com um <b>\033[m</b>. Um texto colorido de verde no terminal pode ser feito assim:</p><br /><br /><br /><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpkBg7UaDkRjYn2JfT-jUlhqOXTKRp6kKGvAI_3p8lAA-KOfRF2H_eDMaVCJMnw8ceG0EYR1aSD3p4-6wq8tCI-uGIYGXlPrR-RCscYQV789EC8qWhn0zySDEjqBPXKLOSuQNiWikcE9k/s1600/hello_world_verde.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 247px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpkBg7UaDkRjYn2JfT-jUlhqOXTKRp6kKGvAI_3p8lAA-KOfRF2H_eDMaVCJMnw8ceG0EYR1aSD3p4-6wq8tCI-uGIYGXlPrR-RCscYQV789EC8qWhn0zySDEjqBPXKLOSuQNiWikcE9k/s400/hello_world_verde.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5475937067371563666" /></a><br /></div><br /><p>Para quem não conseguir visualizar a imagem, o texto no terminal é:</p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">hugo@hugo-laptop:~$ echo -e "\033[32mHello World (verde)\033[m"<br />Hello World (verde)<br />hugo@hugo-laptop:~$<br /></pre><br /><p>Agora chegou a hora de juntar tudo num lugar só!</p><br /><br /><h2>Mostrando o git branch colorido no prompt</h2><br /><p>Os comandos aqui usados já foram explicados, então o código segue:</p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">function git_branch_name() {<br /> git branch 2>/dev/null | grep -e '^*' | sed -E 's/^\* (.+)$/(\1) /'<br />}<br /><br />function show_colored_git_branch_in_prompt() {<br /> PS1="\[\033[01;32m\]\u@\h:\[\033[01;34m\]\w\[\033[31m\]\$(git_branch_name)\[\033[m\]$ "<br />}<br /><br />show_colored_git_branch_in_prompt<br /></pre><br /><p>Adicione este trecho ao <code>~/.bashrc</code> e seja feliz!</p><p><br /><br /></p><p>Caso você queira ver as modificações sem ter que abrir outro terminal, use o comando <code>source</code>:</p><br /><pre class="prettyprint" style="padding-top: 2px; padding-right: 2px; padding-bottom: 2px; padding-left: 2px; border: 1px solid black; overflow-x: auto; overflow-y: auto;">$ source ~/.bashrc<br /></pre><br /><p></p><br /><br /><p>Peguei a dica nesse post: <a href="http://asemanfar.com/Current-Git-Branch-in-Bash-Prompt">http://asemanfar.com/Current-Git-Branch-in-Bash-Prompt</a> e alterei algumas coias. Os comentários são excelentes!</p><br /><br /><p>Espero que tenham gostado da dica ;-)</p><br /><br /><div><br /><p><strong>Updates:</strong></p><br /><ul><br /><li>Corrigido PS1 pra ser dinâmico, e não estático</li><li>Corrigida duplicação de `function`. Valeu Siminino!</li><br /></ul><br /></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com11tag:blogger.com,1999:blog-6205218321209183542.post-43417277994510789942010-05-20T10:23:00.000-07:002010-05-20T12:13:11.790-07:00Apresentando Retrospectivas<div id="markdown-body"><h2>O que será abordado aqui</h2><br /><p>Eu participava de retrospectivas e até liderava algumas sem conhecer direito, no final acabava sendo algo que não gerava tanto valor e ficavam palavras ao vento. O que eu apresentar aqui no texto é baseado no capítulo 13 do livro Agile Coaching, "Driving Change with Retrospectives" e nos conhecimentos adquirido blogs e livros a fora.</p><br /><h2>Introdução</h2><br /><br />Retrospectivas são usadas desde a era industrial pra analisar o que aconteceu com as equipes e estudar possíveis melhorias. Muitas vezes é criada uma linha do tempo (<em>timeline</em>) pra registrar a evolução da equipe. Em <a href="http://en.wikipedia.org/wiki/Lean_Manufacturing">Lean Manufecturing</a> essa prática é conhecida como <a href="http://en.wikipedia.org/wiki/Kaizen">Kaizen</a>, que significa <em>melhora contínua</em>.<br /><br /><br /><div><img src="http://hugolt.files.wordpress.com/2010/05/kaizen.gif" height="100" /><br /></div><br />Retrospectiva, segundo o <a href="http://www.dicionariodoaurelio.com/dicionario.php?P=Retrospectiva">Aurélio</a> é:<br /><br /><pre><code>s.f. O mesmo que retrospecto</code></pre><br /><br />Enquanto <a href="http://www.dicionariodoaurelio.com/dicionario.php?P=Retrospecto"><strong>retrospecto</strong></a> é definido da seguinte forma:<br /><br /><pre><code>s.m. Vista ou análise de fato passado.</code></pre><br /><br />Segundo a <a href="http://en.wikipedia.org/wiki/Retrospective">Wikipedia</a>, a palavra retrospectiva vem do latim <em>retrospectare</em>, que significa "olhar pra trás". Ou seja, retrospectivas são nada mais, nada menos, que encontros nos quais o objetivo é olhar os fatos decorridos e tentar encontrar pontos que podem ser melhorados e estudar como aplicar tais melhorias, visando aumentar os ganhos e diminuir os desperdícios.<br /><br />Henrik Kniberg diz em seu famoso livro <em>Scrum and XP from the Trenches</em>: <strong>"Sem retrospectivas você percebe que a equipe continua cometendo os mesmos erros de sempre"</strong>. Retrospectivas tratam do processo que a equipe utiliza, são uma maneira de identificar onde as coisas não estão saindo como o esperado e estudar como reduzir os problemas.<br /><br />Muitas equipes que tentam fazer retrospectivas acabam desistindo de fazê-las, pois dizem que não sentiram resultados. O problema é que na verdade quem fez não sabia como fazer uma retrospectiva. Pode parecer estranho, mas justificar pra equipe que restrospectivas são fundamentais não é tão simples. Muita gente entorta o nariz da primeira vez, até ver que funciona.<br /><br />Segundo Rachel Davies e Liz Sedley, autoras do livro <a href="http://www.pragprog.com/titles/sdcoach/agile-coaching">Agile Coaching</a>, as retrospectivas devem ser a primeira prática ágil a ser usada pelas equipes que estão começando a usar métodos ágeis. O motivo é que nas retrospectivas são discutidos vários problemas e durante a próxima iteração a equipe já pode introduzir as mudanças e ver melhorias!<br /><br /><h2>O Papel do Facilitador</h2><br /><br />Toda retrospectiva precisa de alguém pra facilitar o encontro. Alguém que guie a retrospectiva, que consiga extrair os problemas, idéias e soluções da equipe. Tal pessoa é o facilitador da retrospectiva.<br /><br /><h2>Facilitando uma Retrospectiva</h2><br /><br />Cada vez que uma iteração termina deve ser feita uma retrospectiva pra abordar os seguintes tópicos:<br /><br /><ul><li>Quais idéias a equipe teve desde a última iteração?</li><li>Quais áreas a equipe quer focar em melhorar?</li><li>Em quais idéias eles podem trabalhar na próxima iteração?</li><br /></ul>Metade do tempo da retrospectiva deve ser gasto olhando pra iteração passada pra ver o que aconteceu e os porquês. Em seguida idéias são levantadas para que possam ser criados planos de ação <em>(action plans)</em>, que dizem o que deve ser feito pra implantar melhorias.<br /><br />Basicamente facilitar uma retrospectiva é isso, e os próximos passos são integrar à próxima iteração as ações mais prioritárias.<br /><br />Para que uma retrospectiva seja proveitosa, leva tempo e prática. Não adianta tentar consertar muitos problemas numa única iteração - não vai dar certo!<br /><br /><h2>A Retrospectiva Feita nos Dojos</h2><br /><br />É um costume em coding dojos fazer uma retrospectiva no fim. Sempre que chega no tempo combinado da duração do dojo, é feito uma retrospectiva. A maneira mais básica de fazer a retrospectiva é dividir o quadro (ou flip chart) em duas colunas: <em>O Que Foi Bom</em>, <em>O Que Foi Ruim</em>. Algumas pessoas gostam de colocar uma divisão entre as duas colunas pra pegar informações sobre o que pode ser melhorado.<br /><br />Um exemplo de uma imagem de retrospectiva de um dojo com duas colunas pode ser visto na seguinte imagem:<br /><div><center><br /><a href="http://github.com/hugobr/DojoCampos/raw/master/2010_03_24/fotos/24032010011.jpg"><img title="Retrospectiva do DojoCampos do dia 24/03/2010" alt="Imagem de uma retrospectiva" src="http://github.com/hugobr/DojoCampos/raw/master/2010_03_24/fotos/24032010011.jpg" width="500" /></a><br /></center></div><br /><br /><p>O problema é que na retrospectiva que acontece nos dojos ficam muitas palavras ao vento. Na maioria das vezes não dá pra criar um plano de ações para melhorar o processo. A retrospectiva acaba ficando mais como lição e compartilhamento de visões, sem ter, de fato, ações de melhorias. O ponto é que a maioria das retrospectivas feitas nos dojos são, a meu ver, mal aproveitadas.</p><br /><br /><h2>Como Olhar Para O Passado</h2><br /><br />Há algumas maneiras de recolher informações do passado. O objetivo nesse momento da retrospectiva é entender o que aconteceu, e os membros da equipe precisam compartilhar suas histórias individuais e integrá-las com as dos outros membros. Algumas maneiras de alcançar tal objetivo são:<br /><br /><strong>Linha de tempo colorida:</strong> É criada uma linha de tempo no quadro ou em algum lugar onde possa ser colado post-its e escrever os acontecimentos na linha de tempo. Post-its coloridos com frases descritivas são usados para indicar os sentimentos da equipe em determinado lugar na linha de tempo. Normalmente é usada a cor <strong>verde</strong> para o que foi proveitoso, <strong>rosa ou vermelho</strong> para o que foi estressante e <strong>amarelo</strong> para o que for neutro. Talvez seja necessário colocar uma legenda para as cores ao lado da linha de tempo pra que ninguém se perca.<br /><br /><strong>Galeria de arte (art gallery)</strong>: O facilitador pede a equipe que cada um desenhe uma imagem do que o projeto se parece pra eles, depois cola as imagens em algum lugar visível a todos. Assim que todos terminarem o facilitador pede que cada explique o seu desenho. Pode parecer estranho, mas as pessoas são muito boas em encontrar metáforas pro que é difícil de ser explicado com palavras. Um relato interessante citado no livro Agile Coaching foi de uma retrospectiva em que um membro desenhou um boneco de palitinhos dentro de uma caixa, e quando foi explicar pra equipe o desenho ele disse que era assim que ele se sentia no projeto - ele trabalhou muito isolado dos outros, e era como se ele não fizesse mais parte do projeto.<br /><br />Há uma variação de <em>art gallery</em> que o Patrick Kua desenvolveu que é muito interessante, o nome é <a href="http://www.thekua.com/atwork/2008/04/retrospective-exercise-mr-squiggle">Mr. Squiggle</a>.<br /><br />Funciona da seguinte maneira: o facilitador desenha alguns traços em papéis (podem ser usados post-its) e entrega um papel pra cada membro da equipe, contendo os mesmos traços criados pelo facilitador. Dê a equipe 5 minutos pra desenharem nos papéis o que o projeto representa pra eles, usando os rabiscos que o facilitador colocou no papel. Depois peça que cada um explique seu desenho para a equipe.<br /><br />O interessante do Mr. Squiggle é que cada um faz um desenho totalmente diferente, mesmo iniciando com os mesmos traços.<br /><br /><h2>Bad Smells</h2><br /><br /><pre><code>"If it stinks, change it"<br /> Avó do Kent Beck, discutindo sobre como criar os filhos</code></pre><br /> <br />Assim como com código, é possível ver <a href="http://c2.com/cgi/wiki?CodeSmell">Bad Smells</a> em retrospectivas - aqueles indícios de que há algo errado.<br /><br /><strong>Idéias da última iteração são ignoradas</strong> É pedido a equipe novas idéias sem discutir o que aconteceu na última iteração. Isso não funciona, pois os problemas são evitados.<br /><br /><strong>Palavras ao vento</strong> Vários itens estão nas colunas "O que foi bom" e "O que não foi bom", mas nenhuma ação é tomada em relação aos dados recolhidos. No fim das contas a retrospectiva serviu apenas como uma conversa e lição de vida.<br /><br /><strong>Mudar o mundo</strong> Algumas equipes criam listas com coisas a serem melhoradas sem considerar a viabilidade de fazer aquelas ações na próxima iteração. Isso traz desapontamento à equipe, porque não conseguiram fazer o que planejaram, e a cada retrospectiva são adicionadas mais ações.<br /><br /><strong>Ações sem "Donos"</strong> Ações que foram criadas e não possuem donos, algo como "Melhorar a comunicação" e "Fazer mais refactoring", não deveriam ser ações, pois são problemas que devem ser trabalhados. Se não houver discussão, a equipe não vai saber como implementar tais "pseudoações".<br /><br /><strong>Falta de tempo para melhorar</strong> A equipe leva cinco minutos depois de uma apresentação de uma release ou demo pra conversar brevemente sobre os acontecimentos e chama isso de retrospectiva. Esse é um sinal de que a equipe não vê benefícios em retrospectivas.<br /><br /><h2>Peneirando Informações</h2><br /><br />Depois que foram recolhidas informações suficientes da equipe é necessário gerar <em>insights</em>. Caso haja alguma informação que ainda não foi compreendida, a equipe deve esclarecê-la - não deve ser pedido diretamente para a pessoa que escreveu a nota explicar, deve ser pedido à equipe. Caso haja frases genéricas como "Ambiente de testes quebrado" ou "Cliente muito ocupado", deve ser pedido exemplos pra tornar mais fácil de ilustrar o problema pra todos.<br /><br />Depois de andar sobre a timeline procurando por insights é a hora de escolher os tópicos mais importantes pra focar. Uma das técnicas é votação por pontos <em>(dot voting)</em>. Cada membro da equipe tem três pontos que pode colocar em qualquer tópico que ache que é mais prioritário - inclusive pode usar os três pontos em um tópico só. Os tópicos com maior pontuação farão parte do planejamento de ações <em>(action planning)</em>.<br /><br />Após extrair os tópicos que a equipe quer focar, procura-se por melhorias no processo que a equipe possa fazer na próxima iteração.<br /><br /><h2>Olhando pro Futuro</h2><br /><br />A segunda metade da retrospectiva deve olhar pra próxima iteração, que é quando a equipe vai trabalhar o gostaria de mudar no processo. Será necessário mais que concordar que mudanças são necessárias, a equipe deve trabalhar nas ações levantadas pra implantar as mudanças.<br /><br />Antes de começar a criar ações novas, um tempo deve ser dedicado para revisar o que aconteceu com as ações da última retrospectiva. Se não foram terminadas a equipe precisa entender o motivo antes de adicionar criar mais ações. Na maioria dos casos é porque as ações não tinham dono ou porque a equipe "não teve tempo".<br /><br />Um tempo deve ser investido na retrospectiva pra trabalhar num plano de ações realista, que seja claro pra todos da equipe. Para que as ações fiquem prontas a equipe precisa terminá-las. O facilitador combina com a equipe quanto tempo será gasto com as melhorias no processo na próxima interação, lembrando que as ações serão feitas enquanto a equipe continua trabalhando no plano do release, ou seja, enquanto continuam a desenvolver software.<br /><br /><h2>Como Criar O Plano de Ações</h2><br /><br />Assim como no desenvolvimento de software, a equipe deve dar passos de bebê <em>(baby steps)</em> na hora de criar as ações pra serem implementadas na próxima iteração. Nem sempre as ações são problemas que podem ser corrigidos - às vezes são estudos sobre algum problema, estabilizar um estilo de código, etc.<br /><br />Bas Vodde tem <a href="http://www.scrumalliance.org/articles/61-plan-of-action">um texto excelente de como criar planos de ação</a>, que as autoras do livro Agile Coaching resumiram no livro.<br /><br />Para ter ações que funcionam, a equipe precisa, além de identificar o que precisa ser alterado, dizer como serão implementadas as mudanças. O processo de recolher as ações que Bas Vodde usa é o seguinte: cada ação tem um objetivo a longo prazo e uma ação para ser feita agora. Por exemplo:<br /><br /><pre><code>Objetivo a longo prazo: Ter testes de aceitação automatizados<br />Ação para agora: Fulano vai automatizar o teste ABC usando XYZ.</code></pre><br /><br />No exemplo citado por Bas Vodde a equipe consiste de oito membros. Inicialmente cada membro gera um conjunto de ações - separadamente - cada uma com um objetivo a longo prazo e uma ação para ser feita; a equipe tem 10 minutos pra gerar as ações.<br /><br />Após geradas as ações, a equipe se divide em duplas. Durante 10 minutos cada dupla agrupa suas ações e seleciona as 5 mais prioritárias.<br /><br />Depois que as duplas selecionarem 5 ações, são gerados grupos de 4 pessoas. Cada grupo agrupa suas ações e seleciona apenas 4 de todas as 10 ações selecionadas (2 duplas selecionaram 5 ações cada) - durante o limite de 10 minutos.<br /><br />Para finalizar, a equipe inteira reúne-se e de todas as 8 ações selecionadas (2 grupos de 4 pessoas e cada grupo selecionou 4 ações), seleciona as 3 mais importantes pra serem implementadas na próxima iteração.<br /><br />A vantagem dessa técnica é que ela reúne tanto esforço individual quanto em grupo, além de ter que haver um consenso entre todos os membros da equipe sobre quais são as prioridades. Devagar e com passos de bebê. Independente do número de ações geradas inicialmente, no fim, apenas três ações são selecionadas. Selecionar ações demais é um erro, que já foi descrito anteriormente como bad smell <em>(Mudar o Mundo)</em>.<br /><br />Depois da retrospectiva as ações precisam ser planejadas na próxima iteração. A equipe combina como serão priorizadas as ações e post-its com as ações podem ser grudados no quadro, para que não sejam esquecidos durante a próxima iteração.<br /><br /><h2>Um Formato Pra Começar</h2><br /><br />Há vários formatos de retrospectivas, alguns mais complicados que outros. Acima foi descrito um formato, mas não é recomendável que seja usado da primeira vez. Antes da retrospectiva começar é necessário arrumar uma sala pra fazer a retrospectiva e material como canetas, papel e post-its - um quadro seria muito bom.<br /><br />Um exemplo de como dividir a retrospectiva, citado no livro Agile Coaching segue:<br /><ul><li>Revise o objetivo do encontro, e relembre a equipe das regras básicas (5 minutos)</li><li>Crie uma linha de tempo (15 minutos)</li><li>Pegue insights baseado na linha de tempo (15 minutos)</li><li>Selecione tópicos para focar (10 minutos)</li><li>Revise o progresso de ações prévias (5 minutos)</li><li>Gere idéias para melhorias (15 minutos)</li><li>Faça um planejamento de ações (15 minutos)</li><br /></ul>Esse formato é recomendável pra quem quer iniciar retrospectivas, mas usar o mesmo formato sempre não é interessante, pois se torna chato, tanto pra equipe quanto pro facilitador. Então, varie os formatos. Há vários formatos listados na wiki Agile Retrospective e podem ser encontrados em <a href="http://agileretrospectivewiki.org/index.php?title=Retrospective_Plans">http://agileretrospectivewiki.org/index.php?title=Retrospective_Plans</a>.<br /><br /><h2>Diretriz Primária (Prime Directive)</h2><br /><br />Tratando-se de retrospectivas há algumas regras básicas, como em qualquer outra reunião, como: não usar computadores, colocar os telefones no silencioso, esperar a vez pra falar. Além das regras básicas há uma diretriz que é chamada de <a href="http://www.retrospectives.com/pages/retroPrimeDirective.html"><em>prime directive</em></a>, que diz: <strong>"Independente do que nós descobrirmos, entendemos e acreditamos que todos fizeram o melhor que podiam, dado o que sabiam na época, seus conhecimentos e habilidades, os recursos disponíveis, e a situação em questão"</strong>.<br /><br />É claro que o mundo não é perfeito e as pessoas cometem erros. Apesar da diretriz primária parecer dizer que problemas não serão causados por indivídios, é bom deixar claro que as retrospectivas não são o melhor lugar para discutir problemas de perfomance dos membros. Retrospectivas devem focar em como melhorar o processo; caso a performance de algum indíviduo venha à tona, mude o foco de volta para as ações da equipe.<br /><br />Rachel Davies e Liz Sedley recomendam que na primeira vez que for feita uma retrospectiva, seja colado na parede a <em>prime directive</em> e que você explique para a equipe o que ela significa.<br /><br /><h2>Minha Tentativa Com O Mr. Squiggle</h2><br /><br />Ontem (20/05/2010) eu não esperava, mas o <a href="http://nsigustavo.blogspot.com/">Gustavo Rezende</a> me pediu pra fazer uma retrospectiva com os aspiras lá no <a href="http://nsi.iff.edu.br/">NSI</a>, sem preparar <strong>nada</strong>. Eu havia comentado com ele sobre essa técnica de desenhos e ele achou interessante e falou pra eu fazer. Bem, eu não havia preparado nada e era o fim de uma release de um projeto que os nossos aspiras estavam fazendo. Eles fizeram uma demonstração para o suposto cliente, que era o <a href="http://twitter.com/ronaldimamaral">Ronaldo Amaral</a>. Eles pecaram em várias coisas, mas era a primeira vez que eles trabalhavam em equipes e não conheciam as tecnologias e métodos ágeis 3 semanas atrás.<br /><br />O interessante é que foi uma retrospectiva de fechamento, e no fim, eu usei <a href="http://www.thekua.com/atwork/wp-content/uploads/2008/04/template.jpg">os mesmos rabiscos que o Patrick Kua</a> (porém numa disposição diferente): uma bolinha, uma reta na horizontal e outra na vertical.<br /><br /><div><br /><a href="http://hugolt.files.wordpress.com/2010/05/retrospectiva_aspiras.jpg"><img src="http://hugolt.files.wordpress.com/2010/05/retrospectiva_aspiras.jpg" alt="Mr. Squiggle com Aspiras do NSI" title="Imagens da retrospectiva feita com os aspiras no NSI" height="300"/></a><br /></div><br /><br />Foi muito interessante ver que todos fizeram desenhos totalmente diferentes, mas que acabaram refletindo uma coisa só: o quanto eles tinha aprendido enquanto trabalhavam no projeto. Todos relataram sobre o quanto aprenderam, como foi o trabalho em equipe, como estudaram as tecnologias e etc. Como a idéia não era ter próxima iteração, pra mim não havia sentido fazer um planejamento de ações, porque o projeto que eles iniciaram iria parar ali. Mas Ronaldo achou melhor dar continuidade até na sexta-feira (mais 2 dias).<br /><br />Pode parecer muito estranho de primeira, mas esse formato com desenhos <strong>funciona</strong>.<br /><br /><h2>Checklist</h2><br /><br />No livro Agile Coaching há no fim de cada capítulo uma checklist que mostra os pontos principais pra executar com sucesso o que foi descrito no capítulo. No capítulo sobre retrospectivas a checklist se resume a:<ul><li><p>Comece a retrospectiva olhando pro passado para entender o que aconteceu o o porquê. Dê tempo suficiente à equipe para contar a história inteira</p></li><li><p>Gaste a segunda metade da retrospectiva olhando pro futuro e decidindo o que irá no plano de ações</p></li><li><p>Procure por bad smells que estão atrapalhando a equipe a ser mais efetiva. Se as retrospectivas não estão melhorando o processo, pense em como você poderia melhorá-las</p></li><li><p>Ache os problemas que a equipe mais quer consertar. Use a votação por pontos para focar no que a equipe gastará suas energias</p></li><li><p>Não adicione mais ações durante a iteração antes da próxima retrospectiva. Até mesmo duas ou três ações terminadas a cada iteração podem causar um impacto significante por vários meses</p></li><li><p>Se as ações da última retrospectiva não foram finalizadas, procure saber os motivos antes de adicionar mais</p></li><br /></ul><br /><br /><h2>Referências</h2><br /><br />O livro <a href="http://www.pragprog.com/titles/sdcoach/agile-coaching">Agile Coaching</a> é excelente, a maior parte do conteúdo do post é baseado no capítulo 13 dele. Há um livro só sobre retrospectivas, <a href="http://pragprog.com/titles/dlret/agile-retrospectives">Agile Retrospectives</a>. Tem um livro que eu nunca li, o <a href="http://www.dorsethouse.com/books/pr.html">Project Retrospectives</a>, mas já fiz umas pesquisas no <a href="http://www.retrospectives.com/">site deles</a>, que por sinal tem um material muito bom.<br /><br /><div><br /><strong>Updates:</strong><br /><p>Adicionada foto dos desenhos feitos pelos aspiras na retrospeciva (Mr. Squiggle)</p><br /></div><br /></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com1tag:blogger.com,1999:blog-6205218321209183542.post-49331955839723343312010-05-13T12:36:00.002-07:002010-05-14T04:28:51.057-07:00Gerenciando ambientes virtuais e pacotes python de forma fácil<div id="markdown-body"><p>Bem, eu estou devendo há um tempo um post sobre integração entre a Python C/API e a Ruby C/API, mas esse post vai ficar no forno mais um tempinho, porque eu tive um insight maneiro e quero compartilhar.</p><p>Ontem eu estava dando uma olhada no <a href="http://www.doughellmann.com/projects/virtualenvwrapper/">virtualenvwrapper</a>, por recomendação do <a href="http://hugomaiavieira.com/">Hugo Maia Vieira</a> e aproveitei pra fazer umas brincadeirinhas com ele junto ao <a href="http://pip.openplans.org/">pip</a>.<br />Vou explicar a idéia de cada projeto envolvido nessa brincadeira e mostrar como criar uma maneira simples de usar ambientes virtuais personalizados e gerenciar pacotes <a href="http://python.org/">Python</a> <em>(python packages)</em>.</p><br /><br /><h2>pip</h2><br />pip significa "pip install [Python] packages", ou seja, é um instalador de pacotes Python. O instalador de pacotes que já está padronizado entre os pythonistas é o <a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a>, eu sei. Porém, quem nunca teve problemas com o <code>easy_install</code>? Quem nunca teve problemas pra desinstalar um pacote? Oh shit! Como assim o <code>easy_install</code> não desinstala? A maneira de "desinstalar" pacotes no <code>easy_install</code> é dizer que o pacote é multiversionado, e ele ainda reside no sistema mesmo assim. O que eu costumava fazer era ir lá na pasta onde ficavam meus pacotes python e remover os arquivos e remover a entrada do <code>easy-install.pth</code> (que guarda as referências do caminhos dos pacotes). Eu até criei um <a href="http://github.com/hugobr/easy_uninstall">easy_uninstall</a> pra remover meus pacotes :-).<br /><p>Esse ano eu estou participando do <a href="http://code.google.com/soc/">Google Summer of Code</a> e vou trabalhar no <a href="http://pip.openplans.org/">pip</a>! Muito provavelmente vou blogar (num futuro próximo) sobre o <code>pip</code> e o que eu ando fazendo nele e o que eu tenho aprendido com o pessoal do projeto. Vai ser uma grande oportunidade pra mim e vou tentar aproveitar o máximo.</p><p>O objetivo do <a href="http://pip.openplans.org/">pip</a> é ser um substituto do <a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a>, mas com muito mais funcionalidades. Vou citar algumas coisas que o <code>pip</code> faz, pondo o nome do comando no cabeçalho.</p><br /><br /><h3>pip install</h3><br /><p>O nome já diz tudo: instala algum pacote (ou alguns).</p><code>$ pip install PACOTE_DESEJADO</code><br /><br /><h3>pip uninstall</h3><br /><p>Uma coisa básica é que o <code>pip</code> desinstala pacotes! Que maravilha, não? O <code>easy_install</code> não faz nem isso!</p><pre><code><span class="Apple-style-span" style="font-family:Georgia, serif;font-size:130%;"><span class="Apple-style-span" style="font-size: 16px; white-space: normal;"><br /></span></span> $ pip uninstall PACOTE_DESEJADO</code></pre><br /><h3>pip freeze</h3><br /><br />A idéia é que você às vezes precisa saber quais pacotes você tem instalado no sistema, e o comando <code>freeze</code> lista todos os pacotes instalados no python em que o <code>pip</code> foi rodado.<br /><pre><code>$ pip freeze</code></pre><br /><br /><h3>pip bundle</h3><br /><br />O <code>pip</code> consegue criar <em>bundles</em>. Bundles são pacotes que contém vários pacotes. A idéia é criar um pacotão com tudo necessário pra instalar um software - dependências e etc. Ano passado eu trabalhei em um sistema que ia ser implantado em Angola e no local que ia ser instalado o sistema não havia conexão de internet boa (era 56k) e não era garantido de chegar lá em Angola e conseguir usar a internet. O que a minha equipe fez foi criar um pacotão com todas dependências de sistema e outro pacotão com todas as dependências dos pacotes python. Os meus amigos <a href="http://twitter.com/dmpinheiro">Diego Manhães</a> e <a href="http://twitter.com/argentinomota">Vanderson Mota</a> ficaram responsáveis por isso, e eu garanto que não foi trivial.<br /><br />Usando o <code>pip</code> essa tarefa se torna fácil, porque é possível criar um pybundle com os pacotes (e suas respectivas dependências). Por exemplo:<br /><br /><pre>$ pip bundle pycukes.pybundle pycukes</pre><br /><br />E para instalar no sistema (sem a necessidade de uma conexão de internet), basta levar o arquivo pycukes.pybundle num pendrive ou dvd e fazer:<br /><br /><pre><code>$ pip install pycukes.pybundle</code></pre><br /><br />E nesse caso <strong>todas</strong> as dependências serão instaladas junto ao pycukes.<br /><br /><h3>pip search</h3><br /><br />Sabe aquele dia que um <code>apt-cache search</code> salva a sua vida? Então, o <code>pip</code> também tem um comando <code>search</code> que pode salvar você! É como se você tivesse ido ao <a href="http://pypi.python.org/">PyPI</a> e digitado alguma coisa no campo de busca e clicado no botão Search. Você pode ver os nomes dos pacotes e as descrições dos mesmos.<br /><br /><pre><code>$ pip search TERMO_DA_BUSCA</code></pre><br /><br /><br /><h2>virtualenv</h2><br />O virtualenv cria ambientes virtuais pra você usar um interpretador Python sem ser o do sistema. Quem nunca bagunçou o Python do sistema quando quis fazer alguma brincadeira? Então, o <a href="http://virtualenv.openplans.org/">virtualenv</a> veio pra solucionar esse e outros problemas. Você não precisa mais de ser superusuário pra instalar pacotes. Você pode ter quantos interpretadores python você quiser, e cada um deles pode ter pacotes diferentes. Ou seja, você consegue isolar um ambiente pra instalar e usar pacotes python.<br /><br /><br />Criar um ambiente virtual é muito simples:<br /><br /><pre><code>$ virtualenv meu_ambiente</code></pre><br /><br />Porém, pra usar algum ambiente virtual é necessário <strong>ativar</strong> esse ambiente. Você pode fazer da seguinte forma:<br /><br /><pre><code>$ source CAMINHO/PARA/meu_ambiente/bin/activate<br /><br />ou<br /><br />$ . CAMINHO/PARA/meu_ambiente/bin/activate<br /></code></pre><br /><br />Após isso você verá que que o texto do seu terminal foi modificado (variável de ambiente <code>$PS1</code>), e lá tem o nome do seu ambiente entre parênteses. Agora você pode instalar o que quiser ali e apagar o que quiser! Fazer qualquer tipo de experimento.<br /><br />O único problema nessa abordagem é que você ainda aproveita os pacotes instalados no python do sistema. A maneira de solucionar isso é dizendo que você quer criar um ambiente virtual que não tem nenhum pacote aproveitado do sistema:<br /><br /><pre><code>$ virtualenv --no-site-packages meu_ambiente</code></pre><br /><br />Imagina que você criou um ambiente virtual e quer usar o <code>pip</code> nele, você só precisa USAR! O virtualenv já vem com o <code>pip</code> instalado. Mas caso você queira atualizar o <code>pip</code>, faça um:<br /><br /><pre><code>$ pip install -U pip</code></pre><br /><br />Sempre que você quiser sair do ambiente virtual, chame o <code>deactivate</code>:<br /><br /><pre><code>$ deactivate</code></pre><br /><br />E voltará ao ambiente normal.<br /><br />Agora você já pode ser feliz com seus pacotes python e fazer o experimento que quiser, e ter quantos ambientes virtuais (isolados) você quiser. Bom, não?!<br /><br /><br /><br /><h2>virtualenvwrapper</h2><br /><br />Quem já está acostumado a usar o <a href="http://virtualenv.openplans.org/">virtualenv</a> sabe que é um saco ter que lembrar os caminhos dos ambientes e ficar dando <code>source</code> no caminho do <code>activate</code>. Outra coisa chata é quando você precisa ir pra pasta de <code>site-packages</code> do ambiente virtual. Pensando nessas coisinhas enjoadas um cara pegou e criou um script que adiciona várias funcionalidades ao <code>virtualenv</code>, o <a href="http://www.doughellmann.com/projects/virtualenvwrapper/">virtualenvwrapper</a>. A instalação do <code>virtualenvwrapper</code> é simples:<br /><br /><pre><code>$ pip install virtualenvwrapper</code></pre><br /><br />Porém, ainda não dá pra sair usando. Você precisa carregar o script (<code>virtualenvwrapper.sh</code>) sempre que quiser usar os recursos do <code>virtualenvwrapper</code>. No fim das contas é melhor adicionar ao seu <code>~/.bashrc</code>. Depois de instalar o <code>virtualenvwrapper</code> com o <code>pip</code> ou <code>easy_install</code> (eu usei o python do sistema), faça:<br /><br /><pre><code>$ echo "source `which virtualenvwrapper.sh`" >> ~/.bashrc<br />$ mkdir ~/.virtualenvs<br /></code></pre><br />E você criará uma pasta (a padrão) pra armazenar os ambientes virtuais e sempre terá os comandos do virtualenvwrapper disponíveis.<br /><br />Depois de reiniciar o terminal, você já pode usar o <code>virtualenvwrapper</code>! Digite:<br /><br /><pre><code>$ workon</code></pre><br /><br />E você provavelmente vai ver uma linha em branco, porque você ainda não tem nenhum ambiente virtual criado com o virtualenvwrapper.<br /><br /><br /><h3>mkvirtualenv</h3><br />O comando <code>mkvirtualenv</code> cria um ambiente virtual baseado no nome que você passar, e você pode passar os mesmos parâmetros que são passados ao <code>virtualenv</code>.<br /><br /><pre><code>$ mkvirtualenv --no-site-packages meu_ambiente</code></pre><br /><br />Quando você digitar o comando acima criará um ambiente virtual com nome de <code>meu_ambiente</code>, que não compartilha pacotes com o python do sistema e irá automaticamente ativar o ambiente.<br /><br /><br /><h3>rmvirtualenv</h3>Quando não houver mais interesse em usar um ambiente virtual, ele pode ser apagado com o comando <code>rmvirtualenv</code>. É necessário estar com o ambiente em questão desativado - caso esteja ativado use o <code>deactivate</code>.<br /><br /><pre><code>$ rmvirtualenv meu_ambiente</code></pre><br /><br /><h3>workon</h3><br /><br />O comando <code>workon</code> quando chamado sem parâmetros mostra todos os ambientes virtuais existentes. Mas quando chamado com o nome do ambiente virtual, ativa o ambiente e executa os hooks (caso existam).<br /><br /><pre><code>$ workon # lista os ambientes virtuais<br />$ workon meu_ambiente # ativa o ambiente virtual meu_ambiente</code></pre><br /><br /><h3>cdvirtualenv</h3><br />Muda o diretório atual para o diretório do ambiente virtual. Por exemplo, você está na pasta <code>/tmp</code> e quer ir pra pasta do ambiente <code>meu_ambiente</code>:<br /><br /><pre><code>(meu_ambiente)hugo@hugo-laptop:/tmp$ pwd<br />/tmp<br />(meu_ambiente)hugo@hugo-laptop:/tmp$ cdvirtualenv<br />(meu_ambiente)hugo@hugo-laptop:~/.virtualenvs/meu_ambiente $ pwd<br />/home/hugo/.virtualenvs/meu_ambiente</code></pre><br /><br /><h3>cdsitepackages</h3>O comando <code>cdsitepackages</code> muda do diretório atual para o diretório de <code>site-packages</code> do ambiente virtual.<br /><br /><pre><code>$ cdsitepackages</code></pre><br /><br /><br /><h3>lssitepackages</h3>O comando <code>lssitepackages</code> faz um <code>ls</code> na pasta <code>site-packages</code>.<br /><br /><pre><code>$ lssitepackages</code></pre><br /><br /><br /><h3>cpvirtualenv</h3>Quando houver necessidade de clonar um ambiente virtual, seja porque você precisa basear-se nos pacotes já instalados ou por qualquer outro motivo, use o <code>cpvirtualenv</code>.<br /><br /><pre><code>$ cpvirtualenv meu_ambiente meu_ambiente_clonado</code></pre><br /><br /><br /><br /><h2>Hooks</h2><br /><br />Hooks são scripts que são ativados antes, depois ou durante o acontecimento de um evento. Por exemplo, no <a href="http://git-scm.com/">Git</a> você pode criar um script pra que após cada <code>push</code> executado no repositório diga ao servidor de integração contínua pra rodar o build.<br /><br />No virtualenvwrapper existem hooks também, com a mesma idéia. A documentação do virtualenvwrapper documenta os hooks na área de <a href="http://www.doughellmann.com/docs/virtualenvwrapper/scripts.html">Per-User Customization</a>. Vou explicar apenas dois deles, o <code>postactivate</code> e o <code>mpostmkvirtualenv</code>.<br /><br /><h3>postactivate</h3><br /><br />É um shell script que você deve colocar na sua <code>$WORKON_HOME/postactivate</code> - no nosso caso <code>$WORKON_HOME</code> será <code>~/.virtualenvs</code>. O caso abaixo muda o diretório corrente para o diretório PASTA sempre que algum ambiente virtual for ativado:<br /><br /><pre><code>$ echo 'cd PASTA_QUALQUER' >> $WORKON_HOME/postactivate</code></pre><br /><br /><h3>postmkvirtualenv</h3><br /><br />Uma das dicas que o Doug Hellmann, o autor do virtualenvwrapper, dá na documentação é que às vezes você precisa instalar alguns pacotes pra ter seu ambiente virtual pronto pra usar. Eu fiz isso. Sempre que eu crio um ambiente virtual alguns pacotes são instalados. No meu caso eu ainda fiz mais, eu adicionei um link pra um pacote python que é instalado junto ao Ubuntu (no caso o GTK e o Cairo, pra eu usar o pynotify no ambiente virtual).<br /><br />Vamos fazer um caso simples: atualizar o <code>pip</code>, instalar o <code>ipython</code> e o <code>nosetests</code>.<br /><br /><pre><code>$ echo 'pip install -U pip' >> $WORKON_HOME/postmkvirtualenv<br />$ echo 'pip install ipython nose' >> $WORKON_HOME/postmkvirtualenv</code></pre><br /><br />Agora sempre que um ambiente virtual for criado ele atualizará o <code>pip</code> do ambiente virtual e instalará no mesmo ambiente o pacote <code>ipython</code> e <code>nose</code>.<br /><br /><br /><h2>Peon</h2><br /><br />Imagine que você quer executar algum comando sempre que algum arquivo for modificado num determinado diretório. Como faz? Bem, você pode criar um script que cria um checksum baseado no somatório do tamanho de cada arquivo e na data de modificação. Bem, é assim que todo mundo faz. O Jeff Winkler teve a idéia de fazer um <a href="http://jeffwinkler.net/2006/04/27/keeping-your-nose-green">script que ficava procurando por mudanças em arquivos terminados em <code>.py</code></a> e quando havia modificação, rodava o <code>nosetests</code>. Ele chamou o script de <a href="http://jeffwinkler.net/2006/04/27/keeping-your-nose-green">nosy</a>.<br /><br /><br /><br />O Bernardo Heynemann acabou pegando a idéia do Jeff e criando o <a href="http://github.com/heynemann/peon">peon</a>, que busca recursivamente por modificações em arquivos terminados em <code>.py</code> e usa o <code>pynotify</code> pra mostrar um alerta, caso o comando passado retorne algum status code diferente de zero.<br /><br />Pra instalar o <a href="http://github.com/heynemann/peon">peon</a> você pode baixar o projeto no github, cloná-lo ou instalá-lo através do arquivo compactado gerado pelo github:<br /><br /><pre><code>$ git clone http://github.com/heynemann/peon.git<br />$ cd peon<br />$ pip install .<br /><br />ou<br /><br />$ pip install http://github.com/heynemann/peon/zipball/master</code></pre><br /><br />Para usar o <code>peon</code> é super simples, basta chamá-lo passando o comando que você quer que seja executado quando alguma modificação for feita. No meu caso, eu queria que o <code>peon</code> rodasse um script que fazia build e rodava os testes de um projeto, e caso houvesse alguma falha ou erro no script de build, mostrasse a notificação com o pynotify. No meu caso era um <code>Makefile</code> que o <code>peon</code> rodava. Era basicamente:<br /><br /><pre><code>$ peon make</code></pre><br /><br /><h3>O meu problema</h3><br /><br />O pynotify é um pacote instalado pelo Ubuntu, sob o pacote do GTK e quando eu criava um ambiente virtual totalmente isolado (<code>--no-site-packages</code>) eu não tinha acesso ao GTK e nem ao Cairo (dependência) e assim, não tinha como usar o pynotify pra exibir os alertas.<br /><br /><h3>A minha solução</h3><br /><br />A primeira coisa é que eu precisava instalar o <code>peon</code> sempre que eu criasse um ambiente virtual. Fiz isso usando o <code>postmkvirtualenv</code>. Outra coisa que eu acabei fazendo foi criar um link simbólico dentro dos meus <code>site-packages</code> apontando pro GTK e pro Cairo. A solução que eu cheguei foi usar o <code>postmkvirtualenv</code> pra criar os links simbólicos e adicionar às entradas devidas no <code>easy-install.pth</code>.<br /><br />Ok, falei um monte de coisas. Mas... e aí, como eu faço isso? A primeira coisa é instalar o <code>peon</code>. Uma das features do github é que ele oferece download dos repositórios de forma compactada. Assim, pra instalar o <code>peon</code> basta um:<br /><br /><pre><code>$ echo 'pip install http://github.com/heynemann/peon/zipball/master' >>\<br />> $WORKON_HOME/postmkvirtualenv</code></pre><br /><br />Agora a parte complicada é fazer os links simbólicos e adicionar as entradas no <code>easy-install.pth</code>.<br /><br /><pre><code>$ echo "<br />> cwd=`pwd`<br />> cdsitepackages<br />> ln -s /usr/lib/pymodules/python2.6/gtk-2.0 .<br />> ln -s /usr/lib/pymodules/python2.6/cairo .<br />> sed -i '1a ./gtk-2.0' easy-install.pth<br />> sed -i '1a ./cairo' easy-install.pth<br />> cd $cwd<br />> " >> $WORKON_HOME/postmkvirtualenv</code></pre><br /><br />A primeira linha, <code>cwd=`pwd`</code>, e a última, <code>cd $cwd</code> foram adicionadas pra ser possível voltar pro diretório atual depois de executar o hook.<br /><br />Agora já é possível usar o <code>peon</code> com ambientes virtuais sem problemas!<br /><p>Faça o teste ;-)</p><br /><br /><h3>O meu objetivo com isso</h3><br /><br />No fim das contas eu acabei criando um <code>postmkvirtualenv</code> que instala alguns pacotes, inclusive o <code>peon</code>, e cria os links simbólicos. Eu sempre crio os links e instalo o <code>peon</code> porque o meu objetivo com os ambientes virtuais é ter um ambiente virtual pra cada projeto que eu contribuo, assim, cada projeto é totalmente isolado do outro e eu tenho um alerta caso os testes não sejam executados com sucesso em algum momento.<br /><br /><br /><h2>Observações</h2><br /><br />Tudo que eu falei aqui está relacionado a Python 2.x. Todos os lugares onde o <code>pip</code> foi usado apenas pra fazer instalação de pacotes do PyPI, o <code>easy_install</code> poderia ter sido usado (apesar de desencorajado!).<br /><br /><br /><h2>Referências</h2><br /><br />A documentação do <a href="http://pip.openplans.org/">pip</a> tem bastante informação e o pessoal (inclusive eu) está sempre online no #pip na freenode.<br /><br /><br />Há um post excelente pra quem quer ver o <a href="http://www.doughellmann.com/projects/virtualenvwrapper/">virtualenvwrapper</a> na prática: <a href="http://mathematism.com/2009/jul/30/presentation-pip-and-virtualenv/">http://mathematism.com/2009/jul/30/presentation-pip-and-virtualenv/</a><br /><p>Nesse mesmo post há um screencast muito interessante também!</p><br /><p>Até o próximo post ;-)</p><br /><br /><br /><div><br /><strong>Updates</strong>:<br /><ul><br /><li>corrigido erro relacionado a aspas no echo. Valeu <a href="http://hugomaiavieira.com">Hugo Maia</a> e <a href="http://blog.justen.eng.br/">Álvaro</a>!</li><br /><li>corrigido erro de portugues: s/enjuado/enjoado/g Valeu <a href="http://hugomaiavieira.com">Hugo Maia!</a></li><br /></ul><br /></div><br /><br /><br /></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com9tag:blogger.com,1999:blog-6205218321209183542.post-62266438269925576682010-03-01T15:08:00.000-08:002010-03-01T15:15:08.690-08:00Introdução à Ruby/C API<div id="markdown-body"><p>Em <a href="http://ruby-lang.org/">Ruby</a> há também formas de estender e embarcar o interpretador. Porém, diferentemente das <a href="http://docs.python.org/c-api">documentações do Python</a>, a documentação disponível em Ruby sempre se refere aos fatos como "estender o interpretador ruby", ou "ruby c extension", raramente falam exatamente sobre embarcar <em>(embed)</em>. Os motivos para usar a Ruby API são os mesmos motivos que os para usar a Python/C API.</p><p>O texto abordará os mesmos tópicos do <a href="http://hltbra.blogspot.com/2010/02/introducao-pythonc-api.html">post anterior sobre a Python/C API</a> e referenciará por vezes o post anterior. A versão do interpretador coberta pelo texto é a 1.8.</p><h1>O básico da Ruby API</h1><p>Ruby é uma linguagem dinâmica, assim como Python, e não precisa de especificações de tipo. Sendo assim, existe um tipo genérico quando trabalha-se com a a API: <code>VALUE</code>. Diferentemente da Python/C API não é usado um ponteiros pro tipo genérico, é simplesmente <code>VALUE</code>.</p><p>Na API não há uma exclusividade de convenção de nomes - nem tudo inicia-se com <code>rb_</code>. Há macros definidas como <code>RSTRING</code>, <code>StringValue</code> e chamadas como <code>rb_define_module</code>. Mas pode-se identificar que todas as chamadas a funções da API começam com <code>rb_</code> ou <code>ruby_</code>.</p><p>Quando a intenção é embarcar o interpretador temos que iniciá-lo e finalizá-lo. Podemos fazer isso através das funções <code>ruby_init</code> e <code>ruby_finalize</code>, que iniciam e finalizam o interpretador ruby, respectivamente.</p><p>A Ruby API pode ser acessada através do cabeçalho <code>ruby.h</code>, que varia a localização em diferentes sistemas e eu conheço apenas uma maneira longa de achar o diretório, que é através do módulo <code>rbconfig</code>, que o <code>mkmf</code> usa pra achar os arquivos. O comando poderia ser feito em uma chamada longa ao interpretador diretamente na linha de comando como segue:</p><pre><code>hugo@hugo-laptop:~$ ruby -r rbconfig \<br />> -e "puts Config::MAKEFILE_CONFIG['topdir']"<br />/usr/lib/ruby/1.8/i486-linux<br />hugo@hugo-laptop:~$</code></pre><p>Isso significa que na minha máquina o arquivo <code>ruby.h</code> está na pasta <code>/usr/lib/ruby/1.8/i486-linux</code>.</p><p>Incluir o cabeçalho <code>ruby.h</code> cabeçalho implica em incluir diversos outros, como <code><stdio.h></code>, <code><stdlib.h></code>, <code><string.h></code>, <code><limits.h></code> (se disponíveis).</p><p><strong>DICA:</strong> Inclua sempre o cabeçalho <code>ruby.h</code> antes de qualquer cabeçalho, pois o Ruby define algumas <em>pre-processor definitions</em> nos cabeçalhos padrões (pelo menos no GNU/Linux!).</p><h2>Exemplo #1 - embarcando o interpretador: usando o método <code>upcase</code></h2><p>O exemplo tem a finalidade de transformar uma string minúscula em uma maiúscula, usando o interpretador Ruby pra isso. Em Ruby o método <code>upcase</code> está definido na classe <code>String</code>. Faremos então uma conversão do tipo C pra uma string em Ruby e chamaremos em seguida o método <code>upcase</code>:</p><pre><code>#include "ruby.h"<br /><br />int main() {<br /> VALUE string_convertida,<br /> resultado;<br /> ID upcase_id;<br /> char *string_minuscula = "hugo";<br /> ruby_init();<br /> upcase_id = rb_intern("upcase");<br /><br /> string_convertida = rb_str_new2(string_minuscula);<br /> resultado = rb_funcall(string_convertida, upcase_id, 0);<br /> printf("antes: %s, depois: %s\n", string_minuscula, \<br /> StringValuePtr(resultado));<br /><br /> ruby_finalize();<br /> return 0;<br /><br />}<br /></code></pre><br /><p>O primeiro passo foi incluir o cabeçalho <code>ruby.h</code> pra ter acesso à API. Depois foram definidas duas variáveis do tipo <code>VALUE</code>, onde <code>string_convertida</code> guardará a string convertida de C pra Ruby e <code>resultado</code> guardará o retorno do método <code>upcase</code>.<br />A variável <code>upcase_id</code> merece uma atenção especial. Na Ruby API pra passar <em>nomes</em>, em muitos dos casos, não pode ser através de uma string, mas através de um <code>ID</code>. Nesse caso, essa variável guardará o ID do nome <code>upcase</code>.<br />A variável <code>string_minuscula</code> guarda o valor "hugo", em minúsculo, pra ser convertido pra maiúsculo.</p><p>A chamada a função <code>ruby_init</code> é pra iniciar o interpretador Ruby pra termos acesso as facilidades do mesmo. A chamada a <code>rb_intern</code> retorna o ID do nome "upcase" caso exista, caso contrário ele criará na tabela de símbolos o id referente ao nome - por isso tem que ser chamado após a inicialização do interpretador.</p><p>A função <code>rb_str_new2</code> cria uma string em ruby, passando como argumento o valor em C.</p><p><code>rb_funcall</code> chama uma função em um determinado objeto. O primeiro parâmetro é o objeto em que reside a função, o segundo é o ID do nome da função, o terceiro o número de parâmetros e daí em diante os parâmetros. No caso acima não era necessário passar parâmetros, assim, o terceiro argumento foi 0 e não houve mais nenhum argumento após este.</p><p>A macro <code>StringValuePtr</code> retorna uma string <em>(char *)</em> com o valor da string em ruby. Após tudo isto o interpretador é finalizado, chamando <code>ruby_finalize</code>.</p><p>Os protótipos podem ser entendidos como:</p><pre><code>ID rb_intern(char *nome);<br />VALUE rb_str_new2(char *string);<br />VALUE rb_funcall(VALUE obj, ID nome_id, int argc, ...);<br />char* StringValuePtr(VALUE string);</code></pre><p>O executável pode ser gerado usando o GCC da seguinte maneira:</p><pre><code>hugo@hugo-laptop:~/Desktop/posts/rb$ gcc -o upcase upcase.c \<br />> -I/usr/lib/ruby/1.8/i486-linux -lruby1.8<br />hugo@hugo-laptop:~/Desktop/posts/rb$ ./upcase<br />antes: hugo, depois: HUGO<br />hugo@hugo-laptop:~/Desktop/posts/rb$</code></pre><p>A opção <code>-lruby1.8</code> varia de sistema pra sistema, mas normalmente a opção pra linkar a biblioteca do interpretador é <code>-lruby</code> ou <code>-lrubyVERSAO</code>.</p><p>Algo correspondente em Ruby seria:</p><pre><code>hugo@hugo-laptop:~/Desktop/posts/rb$ irb<br />irb(main):001:0> string_minuscula = "hugo"<br />=> "hugo"<br />irb(main):002:0> resultado = string_minuscula.upcase<br />=> "HUGO"<br />irb(main):003:0> puts "antes: #{string_minuscula}, " \<br />irb(main):004:0* "depois: #{resultado}"<br />antes: hugo, depois: HUGO<br />=> nil<br />irb(main):005:0></code></pre><h2><br /></h2><h2>Exemplo #2 - estendendo o interpretador: Criando um módulo com funções matemáticas</h2><p>Nesse exemplo criaremos um módulo <code>Matematica</code> que conterá duas funções: <code>fatorial</code> e <code>raiz_quadrada</code>.</p><p>Em Ruby todo módulo de extensão precisa de apenas uma coisa: uma função <code>Init_NOMEDOMODULO</code>. O código segue:</p><pre><code>#include "ruby.h"<br />#include <math.h><br /><br />int fatorial_c_puro(int n)<br />{<br /> if (n <= 1)<br /> return 1;<br /> return n * fatorial_c_puro(n-1);<br />}<br /><br />VALUE raiz_quadrada(VALUE self, VALUE x)<br />{<br /> double raiz = sqrt(NUM2DBL(x));<br /> return rb_float_new(raiz);<br />}<br /><br />VALUE fatorial(VALUE self, VALUE x)<br />{<br /> int x_int = NUM2INT(x);<br /> return INT2NUM(fatorial_c_puro(x_int));<br />}<br /><br />void Init_matematica()<br />{<br /> VALUE modulo_matematica;<br /> modulo_matematica = rb_define_module("Matematica");<br /> rb_define_module_function(modulo_matematica, \<br /> "fatorial", \<br /> fatorial, \<br /> 1);<br /> rb_define_module_function(modulo_matematica, \<br /> "raiz_quadrada", \<br /> raiz_quadrada, \<br /> 1);<br />}</code></pre><p>A abordagem foi idêntica a usada no post sobre a Python/C API, que consiste em ter 1 função em C puro pra calcular fatorial e duas que usam a API.</p><p>A macro <code>NUM2DBL</code> converte um objeto numérico de ruby pro tipo <code>double</code> em C. A <code>NUM2INT</code> converte um objeto numérico pra um <code>int</code> e <code>INT2NUM</code> converte um <code>int</code> pra <code>Fixnum</code> ou <code>Bignum</code>.</p><p>A função responsável por iniciar o módulo sempre que é feito um <code>require</code> é <code>Init_matematica</code>. Reparem que em Python seria <code>initmatematica</code>, mas em Ruby o prefixo é <code>Init_</code> ao invés de <code>init</code>.</p><p>Dentro da função que inicializa o módulo temos uma variável <code>modulo_matematica</code> que guarda o módulo em si. <code>rb_define_module</code> define um módulo com o valor de <code>Matematica</code> e duas funções <code>fatorial</code> e <code>raiz_quadrada</code>, ambas têm 1 parâmetro. Assim, a função <code>fatorial</code> será acessível da seguinte forma <code>Matematica::fatorial</code>.</p><p>Os protótipos podem ser entendidos como:</p><pre><code>double NUM2DBL(VALUE n);<br />int NUM2INT(VALUE n);<br />VALUE INT2NUM(int n);<br />VALUE rb_define_module(char *nome);<br />void rb_define_module_function(VALUE modulo, \<br /> char *nome, \<br /> VALUE(*funcao)(), \<br /> int argc);</code></pre><p>Agora precisamos gerar o modulo pra ser usado pelo interpretador Ruby. A maneira mais elegante de se fazer isso é usar o módulo padrão <code>mkmf</code>. Porém, as duas maneiras serão mostradas.</p><p>A primeira maneira é através de uma chamada direta ao gcc, que é simples:</p><pre><code>hugo@hugo-laptop:~/Desktop/posts/rb$ gcc -shared matematica.c \<br />> -I/usr/lib/ruby/1.8/i486-linux -o matematica.so -lm<br />hugo@hugo-laptop:~/Desktop/posts/rb$</code></pre><p>A outra maneira é através do <code>mkmf</code>. Essa maneira consiste em criar um script em ruby que é responsável por criar um <code>Makefile</code> que gera o módulo. O arquivo se chamará <code>extconf.rb</code> e o conteúdo será o seguinte:</p><pre><code>require 'mkmf'<br /><br />create_makefile('matematica')</code></pre><p>Isso significa que nós criaremos um <code>Makefile</code> que usará o compilador padrão, criando o arquivo <code>matematica.so</code>, <code>matematica.dll</code> ou <code>matematica.bundle</code> - dependo do sistema. No meu caso é um <code>.so</code>. Após criado o arquivo, basta rodá-lo pra criar o <code>Makefile</code> e depois uma simples chamada ao <code>make</code> cria os arquivos.</p><p>PS.: O arquivo <code>extconf.rb</code> deve estar no mesmo diretório em que os arquivos escritos em C.</p><p><strong>DICA</strong>: Veja a documentação da função <code>dir_config</code> do módulo <code>mkmf</code> aqui: <a href="http://ruby-doc.org/stdlib/libdoc/mkmf/rdoc/files/mkmf_rb.html#M000549">http://ruby-doc.org/stdlib/libdoc/mkmf/rdoc/files/mkmf_rb.html#M000549</a></p><pre><code>hugo@hugo-laptop:~/Desktop/posts/rb$ ruby extconf.rb<br />creating Makefile<br />hugo@hugo-laptop:~/Desktop/posts/rb$ make<br />cc -I. -I/usr/lib/ruby/1.8/i486-linux \<br /> -I/usr/lib/ruby/1.8/i486-linux \<br /> -I. -D_FILE_OFFSET_BITS=64 \<br /> -fPIC -fno-strict-aliasing \<br /> -g -g -O2 -fPIC -c matematica.c<br />cc -shared -o matematica.so upcase.o matematica.o \<br /> -L. -L/usr/lib -L. -Wl,-Bsymbolic-functions \<br /> -rdynamic -Wl,-export-dynamic \<br /> -lruby1.8 -lpthread -ldl -lcrypt -lm -lc<br />hugo@hugo-laptop:~/Desktop/posts/rb$</code></pre><p>É possível testar facilmente se o módulo <code>Matematica</code> está acessível através de um <code>require 'matematica'</code>.</p><pre><code>hugo@hugo-laptop:~/Desktop/posts/rb$ irb<br />irb(main):001:0> require 'matematica'<br />=> true<br />irb(main):002:0> Matematica::fatorial 5<br />=> 120<br />irb(main):003:0> Matematica::raiz_quadrada 2<br />=> 1.4142135623731<br />irb(main):004:0></code></pre><h2><br /></h2><h2>Referências</h2><p>Eu comecei a estudar a Ruby C API através do projeto <a href="http://rubypython.rubyforge.org/">RubyPython</a>, mas pra entender muita coisa eu usei como referência o livro <em>Programming Ruby, 2nd edition</em>, que tem o capítulo 21 dedicado a API. Também usei uma apresentação de slides com o título de <a href="http://java.ociweb.com/mark/NFJS/RubyCExtensions.pdf">Ruby C Extensions</a>, que tem como autor Mark Volkmann. Eu tentei olhar a <a href="http://www.ruby-doc.org/doxygen/current/">documentação no site oficial da linguagem</a>, mas foi difícil de ter acesso e eu recomendo fortemente o livro, tanto pro uso da API quanto pra aprender Ruby e a apresentação mostra muitos pontos rápidamente e com exemplos.</p><p>Num futuro próximo escreverei um post sobre como fazer Ruby se comunicar com Python e vice-versa, com interface em ambos lados. Tentarei mostrar um pequeno exemplo, mas talvez nesse meio tempo eu escreva sobre algo diferente ou até mesmo detalhar mais um pouco uma das duas APIs ou aproveitar o feedback recebido e mostrar algo em que os autores dos comentários que chegaram a mim queiram ver ou aprender.</p><p>Até o próximo post ;-)</p></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com0tag:blogger.com,1999:blog-6205218321209183542.post-54877115647935152922010-02-23T12:25:00.000-08:002010-02-24T11:10:59.567-08:00Introdução à Python/C API<div id="markdown-body"><p>Nas últimas semanas antes do carnaval eu estava estudando um projeto - <a href="http://rubypython.rubyforge.org/">RubyPython</a> - o qual tenho grandes intenções em contribuir, pois visa integrar python e ruby com uma interface em Ruby, algo que eu, pessoalmente, acho interessante.<br />O projeto usa a Python/C API e a Ruby API (ambas em C), assim, eu tive que dar uma olhada nas duas APIs pra poder entender o código.</p><p>Já que eu tenho estudado um pouco das duas APIs vou começar escrevendo sobre a API do Python, porque há tempos estou pra aprende-la e até antes do rubypython não tinha tido coragem pra aprender.</p><p>Este texto tem como público alvo quem já conhece Python e tem uma base na linguagem C. Será abordado a API da linguagem Python 2.5, que é compatível com as versões 2.4 e 2.6. A API da versão 3 é diferente e não será abordada em nenhum lugar no texto.</p><br /><h2>Mas afinal, por que fazer em C?</h2><p>Há duas razões pra usar a Python/C API: escrever <em>módulos de extensão (extension modules)</em> para estender o interpretador Python e <em>embarcar (embed)</em> o interpretador Python (usá-lo como um componente em uma aplicação).</p><p>Pode-se entender módulos de extensão como bibliotecas escritas em C/C++ usadas dentro do interpretador Python; e embarcar o interpretador significa usar as facilidades do interpretador a partir da API para escrever código em C ou C++.</p><p>Uma das maiores vantagens de usar a Python/C API é sem dúvidas performance. Outra vantagem é poder usar bibliotecas já prontas e adaptá-las pra serem usadas com Python.<br />Um exemplo de módulo de extensão é a biblioteca <a href="http://www.blogger.com/www.pythonware.com/products/pil/" title="Python Image Library">PIL</a>.</p><br /><h2>O básico da Python/C API</h2><p>Python é uma linguagem dinâmica e nós não temos que nos preocupamos com tipagem estática quando escrevemos código Python. Assim sendo, a API trata todos objetos Python como sendo de um tipo só: um ponteiro para PyObject: <code>PyObject *</code>.</p><p>Toda a API está disponível através do cabeçalho <code>Python.h</code>, que normalmente fica em <code>/usr/include/pythonVERSAO</code>, mas você pode descobrir facilmente usando o seguinte comando:</p><pre><code>$ python-config --include</code></pre><p>No meu caso eu obtive:</p><pre><code>hugo@hugo-laptop:~$ python-config --include<br />-I/usr/include/python2.5 -I/usr/include/python2.5</code></pre><p>O <code>-I</code> é a opção que deve ser passada ao GCC para incluir esse diretório nas buscas por cabeçalhos.<br />Então, antes de tudo nos nossos módulos de extensão ou antes de embarcar o python, devemos escrever o seguinte:</p><pre><code>#include "Python.h"</code></pre><p><strong>DICA:</strong> Evite usar <code><Python.h></code> (com <> ao invés de "") pra evitar problemas de multi-plataformas.</p><p>Incluir o cabeçalho <code>Python.h</code> implica em incluir também alguns cabeçalhos padrões como: <code><stdio></code>, <code><string.h></code>, <code><errno.h></code>, <code><limits.h></code> e <code><stdlib.h></code> (se disponíveis).</code></p><p><strong>DICA:</strong> Inclua sempre o cabeçalho <code>Python.h</code> antes de qualquer cabeçalho, pois o Python define algumas <em>pre-processor definitions</em> nos cabeçalhos padrões em algumas plataformas.</p><p>Todos os "nomes" visíveis através do cabeçalho <code>Python.h</code> começam com <code>Py</code> ou <code>_Py</code>, sendo os que começam com <em>underline</em> usados pra uso interno e devem ser evitados em código de produção.</p><p>Sempre que for necessário usar algum recurso como bibliotecas/módulos padrões do interpretador Python é necessário inicializá-lo e após todo o uso finalizá-lo. As funções <code>Py_Initialize</code> e <code>Py_Finalize</code> são respectivamente responsáveis por iniciar e finalizar o interpretador.</p><br /><h2>Exemplo #1 - embarcando o interpretador: Usando a biblioteca <code>string</code></h2><p>Para mostrar um caso do uso de Python embarcado vamos usar a biblioteca padrão <code>string</code> para tornar a string "hugo" em "HUGO" usando o método <code>upper</code>:</p><pre>#include "Python.h"<br /><br />int main()<br />{<br /> PyObject *modulo_string,<br /> *string_maiuscula;<br /> char *string_minuscula = "hugo",<br /> *resultado;<br /> Py_Initialize();<br /><br /> modulo_string = PyImport_ImportModule("string");<br /> string_maiuscula = PyObject_CallMethod(modulo_string, "upper", "s", string_minuscula);<br /> resultado = PyString_AsString(string_maiuscula);<br /> printf("antes: %s, depois: %s\n", string_minuscula, resultado); <br /> <br /> Py_Finalize();<br /> return 0;<br />}<br /></pre><p>Primeiro nós incluímos o nosso cabeçalho padrão <code>Python.h</code>, depois definimos duas variáveis do tipo <code>PyObject *</code> que serão usadas posteriormente para armazenar o módulo <code>string</code> e o resultado do método <code>upper</code>; em seguida definimos duas variáveis do tipo <code>char *</code> que armazenarão a nossa string "hugo" e o resultado da chamada ao método <code>upper</code> convertido pra C, para que usássemos com a função <code>printf</code> (perceba que não inclui-se <code><stdio.h></code> pois está implícito).</p><p>Após nossas declarações iniciamos o interpretador Python para que possamos usar uma de suas bibliotecas padrões.</p><p>O módulo <code>string</code> é obtivo através da chamada à função <code>PyImport_ImportModule</code>, que importa um módulo (dos módulos definidos em <code>sys.modules</code>).</p><p>Depois que já temos o módulo <code>string</code> precisamos chamar o método <code>upper</code>, passando como argumento uma única string (indicada por <code>"s"</code>).<br />Quem nos auxilia nesse caso é a função <code>PyObject_CallMethod</code>, que espera como primeiro parâmetro um objeto python, como segundo o nome do método (tipo <code>char *</code>) e em seguida um formato dos parâmetros (que no nosso caso o "s" significa que haverá em seguida apenas UM parâmetro e que será uma string) e por último passamos o nosso tão aguardado parâmetro pro método upper.</p><p>Talvez observando os protótipos destas duas funções os parâmetros fiquem mais claros:</p><pre><code>PyObject* PyImport_ImportModule(const char *name)<br />PyObject* PyObject_CallMethod(PyObject *o, char *method, char *format, ...)<br /></code></pre><br /><p>O retorno da chamada a <code>PyObject_CallMethod</code> no código acima é um objeto python que guardará a nossa string em upper case. Porém, a função <code>printf</code> definida em <code><stdio.h></code> não conhece os <code>PyObject *</code> da vida. Assim é necessário converter o valor de <code>PyObject *</code> pra <code>char *</code>, usando a função <code>PyString_AsString</code>.<br />Por fim encerramos o interpretador Python através da função <code>Py_Finalize</code>.</p><p>Nós temos o código, mas não temos o executável ainda. Usarei o GCC pra compilar esse código (meu fonte é up.c):</p><pre><code>hugo@hugo-laptop:~/pythoncapi$ gcc -o up up.c -I/usr/include/python2.5 -lpython2.5<br />hugo@hugo-laptop:~/pythoncapi$ ./up<br />antes: hugo, depois: HUGO</code></pre><p>A opção <code>-lpython2.5</code> foi usada pra linkar a biblioteca do python2.5.</p><p>Um pouco trabalhoso, não? Se fosse em Python puro (usando a mesma abordagem) seria apenas:</p><pre><code>>>> import string<br />>>> string_minuscula = "hugo"<br />>>> resultado = string.upper(string_minuscula)<br />>>> print resultado<br />HUGO<br /></code></pre><br /><h2>Exemplo #2 - estendendo o interpretador: Criando um módulo com funções matemáticas</h2><p>Módulos de extensão não necessariamente usam as facilidades do interpretador Python, podendo somente criar extensões pro intepretador. Assim, no nosso caso vamos criar apenas duas funções: <code>fatorial</code> e <code>raiz_quadrada</code> e as mesmas serão acessíveis através do módulo <code>matematica</code>.</p><p>Para todo módulo de extensão é necessário uma função <code>initNOMEDOMODULO</code> e uma definição de métodos que o módulo conterá. Vamos ao código:</p><pre>#include "Python.h"<br />#include <math.h><br /><br />int fatorial_c_puro(int n)<br />{<br /> if (n <= 1)<br /> return 1;<br /> return n * fatorial_c_puro(n - 1);<br />}<br /><br />PyObject *raiz_quadrada(PyObject *self, PyObject *n)<br />{<br /> double raiz = sqrt(PyFloat_AsDouble(n));<br /> return PyFloat_FromDouble(raiz);<br />}<br /><br /><br />PyObject *fatorial(PyObject *self, PyObject *n)<br />{<br /> int n_int = PyInt_AsLong(n);<br /> return PyInt_FromLong(fatorial_c_puro(n_int));<br />}<br /><br />PyMethodDef funcoes_matematicas[] = {<br /> {"raiz_quadrada", (PyCFunction)raiz_quadrada, METH_O}, <br /> {"fatorial", (PyCFunction)fatorial, METH_O}, <br /> {NULL, NULL},<br />};<br /><br />void initmatematica()<br />{<br /> Py_InitModule("matematica", funcoes_matematicas);<br />}<br /></pre><p>A primeira função - <code>fatorial_c_puro</code> - foi criada somente pra "limpar" o nosso código e deixar mais simples de entender as chamadas da API e simplesmente retorna o fatorial de um determinado número.</p><p>Toda função do tipo: <code>Py<tipo>_As<tipo></tipo></tipo></code>, como em <code>PyFloat_AsDouble</code> converte do tipo em python pro tipo em C (no caso desta última converte um float em Python pra um double em C). E as funções que ao invés do <code>As</code> possuem o <code>From</code>, como em <code>PyFloat_FromDouble</code> convertem do tipo em C pro tipo em Python.</p><p>Toda função que será usada pelo Python tem como primeiro parâmetro um <code>self</code>, que é o contexto/namespace da função. As funções <code>raiz_quadrada</code> e <code>fatorial</code> recebem apenas um parâmetro, porém o <code>self</code> é obrigatório e não conta no número de parâmetros, é como se não existisse na definição da função.</p><p>Todo módulo tem uma definição de métodos, que são declarados em um array do tipo <code>PyMethodDef</code> que deve ter como último elemento uma struct com pelo menos <code>NULL</code> e <code>NULL</code> pra indicar o fim do array com as definições. No caso da variável <code>funcoes_matematicas</code> as duas primeiras structs tem como primeiro elemento o nome do método, como segundo a função em C (que usa a Python/C API) que é responsável pelo método, o terceiro é uma macro indicando o número de parâmetros e o quarto e último é a docstring, que nós não colocamos e que por padrão é vazia. No caso onde há apenas um parâmetro usa-se <code>METH_O</code> para evitar <em>parsing</em> manual de parâmetros.</p><p>Para facilitar, entenda <code>PyMethodDef</code> como definido da seguinte maneira:</p><pre>typedef struct {<br /> char *nome;<br /> PyCFunction funcao;<br /> int flags;<br /> char *docstring;<br />} PyMethodDef;<br /></pre><br /><p>Vale falar um pouco sobre essa indicação dos parâmetros através de flags. Na API você pode usar algumas indicações de número de parâmetros através de <em>flags</em>, dentre as mais usadas: <code>METH_VARARGS</code>, <code>METH_KEYWORDS</code>, <code>METH_O</code> e <code>METH_NOARGS</code>. Os dois primeiros são bem autoexplicáveis. Neles é necessário fazer o <em>parsing</em> manual dos parâmetros, mesmo que só tenha sido passado um. Pra facilitar nossa vida foi usado <code>METH_O</code> que significa que será recebido apenas um parâmetro.</p><p>Outro ponto é o <em>casting</em> pra PyCFunction. O casting foi usado pra evitar warnings do compilador e nada mais.</p><p>Como todo módulo precisa de uma função de inicialização do módulo, foi criada a função <code>initmatematica</code>, que dentro dela é inicializado o módulo <code>matematica</code> que contém <code>funcoes_matematicas</code> como os métodos do módulo.</p><p>Eu usei o gcc pra gerar o módulo e o python interativo pra mostrar o uso:</p><pre><code>hugo@hugo-laptop:~/pythoncapi$ gcc -shared -o matematica.so\<br />> matematica.c -I/usr/include/python2.5 -lm<br />hugo@hugo-laptop:~/pythoncapi$ python<br />Python 2.5.2 (r252:60911, Jan 20 2010, 23:16:55)<br />[GCC 4.3.2] on linux2<br />Type "help", "copyright", "credits" or "license" for more information.<br />>>> import matematica<br />>>> matematica.fatorial(5)<br />120<br />>>> matematica.raiz_quadrada(2)<br />1.4142135623730951<br />>>></code></pre><p>A opção <code>-shared</code> do gcc gera um objeto sem <em>linkage</em> e a <code>-lm</code> é pra linkar a biblioteca matemática.</p><br /><h2>Referências</h2><p>Quando eu comecei a estudar a Python/C API foi pela documentação oficial do Python 2.5, o qual eu tinha baixado o fonte. Porém, pelo site <em>docs.python.org</em> é possível acessar a documentação oficial da API da última versão do Python (atualmente 2.6): <a href="http://docs.python.org/c-api">http://docs.python.org/c-api</a>. Atualmente eu tenho usado o pdf <a href="http://cilentonline.net/py/Python%20full/api.pdf">Python/C API Reference Manual</a> pra fazer consultas e o mesmo está acessível também pela página da API da versão 2.5 da linguagem: <a href="http://www.python.org/doc/2.5.2/api/api.html">http://www.python.org/doc/2.5.2/api/api.html</a>.</p><br /><p>Esse texto termina aqui, porém tentarei em breve escrever mais sobre a Python/C API e sobre a Ruby API e depois sobre a integração das duas, pra tentar chegar em como o <a href="http://rubypython.rubyforge.org/">RubyPython</a> funciona.</p><br /><p>Até o próximo post ;-)</p></div><br /><br />Updates:<br />24/02/2010 - O Magno Lima me alertou que eu tinha escrito fibonnaci mas tinha implementado um fatorial. Corrigido!Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com4tag:blogger.com,1999:blog-6205218321209183542.post-14339988123835073162010-02-02T07:18:00.000-08:002010-02-23T12:36:42.753-08:00Migrando de Serviço de Blog<div>Estou largando nesse momento o meu blog na Wordpress: <a href="http://hugolt.wordpress.com/">http://hugolt.wordpress.com</a> para usar esse <a href="http://hltbra.blogspot.com/">aqui</a> no <a href="http://blogger.com/">Blogger</a>.</div><div><br /></div><div><b><span class="Apple-style-span" style="font-size:large;">Motivo da mudança</span></b></div><div><span class="Apple-style-span">Eu me cansei de brigar com os htmls no Wordpress, eu gostaria de usar o meu próprio CSS customizado, sem ter que pagar anuidade alguma por isso.</span></div><div><span class="Apple-style-span">Eu começei a escrever meus posts usando </span><a href="http://docutils.sourceforge.net/rst.html"><span class="Apple-style-span">reStructuredText</span></a><span class="Apple-style-span"> e talvez até use </span><a href="http://daringfireball.net/projects/markdown/syntax"><span class="Apple-style-span">Markdown</span></a><span class="Apple-style-span"> em algumas situações, pois é mais cômodo que escrever HTML na mão (e a interface do Wordpress pra escrever posts é meio tosca). Eu até criei um CSS parecidíssimo com o que o </span><a href="http://github.com/"><span class="Apple-style-span">GitHub</span></a><span class="Apple-style-span"> usa pra usar nos arquivos markdowns que eu estava escrevendo e o Wordpress não me deixava personalizar o meu blog!</span></div><div><span class="Apple-style-span"> Além disso tudo a interface do Wordpress pra escrever os posts não é lá grandes coisas, é (atualmente) bem lenta comparada a essa do Blogger.</span></div><div><br /></div><div><b><span class="Apple-style-span" style="font-size:large;">Migração dos Posts</span></b></div><div><span class="Apple-style-span">O Blogger não permite importar blogs de outros serviços diferentes do próprio Blogger -diferente do Wordpress - e isso significa que eu não vou migrar todos os posts antigos pra cá.<br /><br /></span></div><div><b><span class="Apple-style-span" style="font-size:large;">Futuro do Blog</span></b></div><div><span class="Apple-style-span">Espero que com esse novo blog eu blogue mais, pois não tenho mais motivos pra evitar escrever os posts (fora o motivo que sempre tinha: falta de tempo!).</span></div><div><br /></div><div><span class="Apple-style-span">Até o próximo post :-)</span></div>Hugo Lopes Tavareshttp://www.blogger.com/profile/13911328185232480211noreply@blogger.com0