<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <title>Renne Rocha</title>
    <link>http://rennerocha.com</link>
    <description>Compartilhando o que eu faço no meu tempo livre (ou nem tão livre assim)</description>
    <pubDate>Tue, 19 Feb 2013 17:48:08 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Como (não) utilizar formulários no Django</title>
      <link>http://rennerocha.com/2013/02/como-nao-utilizar-formularios-no-django</link>
      <pubDate>Tue, 19 Feb 2013 13:37:00 BRT</pubDate>
      <category><![CDATA[Django]]></category>
      <guid>http://rennerocha.com/2013/02/como-nao-utilizar-formularios-no-django</guid>
      <description>Como (não) utilizar formulários no Django</description>
      <content:encoded><![CDATA[<p>Existe uma <a href="http://www.slideshare.net/pydanny/advanced-django-forms-usage">apresentação</a> muito conhecida,
realizada na <a href="http://pyvideo.org/video/82/djangocon-2011--advanced-django-form-usage">DjangoCon 2011</a>
apresentando diversas práticas para trabalhar com formulários do Django. Muitas dessas dicas são
muito boas e são utilizadas por grande parte da comunidade Django.</p>
<p>O primeiro padrão apresentado tenta simplificar a maneira como construímos e manipulamos
formulários. Eles utilizam como exemplo uma <em>view</em> padrão encontrada na maioria dos projetos:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s">&#39;POST&#39;</span><span class="p">:</span>
        <span class="n">form</span> <span class="o">=</span> <span class="n">MyForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
            <span class="n">do_something</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="s">&#39;/success&#39;</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">form</span> <span class="o">=</span> <span class="n">MyForm</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="s">&#39;template.html&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;form&#39;</span><span class="p">:</span> <span class="n">form</span><span class="p">},</span> <span class="n">request</span><span class="o">=</span><span class="n">request</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<p>Neste exemplo, temos dois blocos <em>if</em> aninhados e a variável <em>form</em> é instanciada em dois
lugares diferentes. A maneira sugerida para simplificá-lo é a seguinte:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">form</span> <span class="o">=</span> <span class="n">MyForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span> <span class="ow">or</span> <span class="bp">None</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
        <span class="n">do_something</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="s">&#39;/success&#39;</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="s">&#39;template.html&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;form&#39;</span><span class="p">:</span> <span class="n">form</span><span class="p">},</span> <span class="n">request</span><span class="o">=</span><span class="n">request</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<p>Neste caso, quando submetemos este formulário, o atributo <em>request.POST</em> é uma
instância de <em>django.http.QueryDict</em>, avaliado como <em>True</em>. Deste modo o formulário
é instanciado com os valores informados pelo usuário preenchidos podendo ser
validado (<a href="https://docs.djangoproject.com/en/dev/ref/forms/api/#bound-and-unbound-forms">bound</a>).</p>
<p>Caso a requisição não seja pelo método POST, este atributo não existe. O
formulário é instanciado com o parâmetro <em>None</em> criando um formulário vazio
(<a href="https://docs.djangoproject.com/en/dev/ref/forms/api/#bound-and-unbound-forms">unbound</a>)
que nunca será válido por não possuir dados.</p>
<p>Aparentemente é uma boa idéia, já que diminuímos a quantidade de linhas de código
melhorando um pouco a legibilidade do código e os pontos onde podemos ter erros.
<strong>Porém, esta solução não funciona em 100% dos casos.</strong></p>
<p>Uma situação onde não podemos utilizar esse padrão é quando temos um formulário
apenas com campos de múltipla escolha como esse:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="n">CHOICES</span><span class="o">=</span><span class="p">[(</span><span class="s">&#39;beatles&#39;</span><span class="p">,</span><span class="s">&#39;John&#39;</span><span class="p">),</span>
         <span class="p">(</span><span class="s">&#39;beatles&#39;</span><span class="p">,</span><span class="s">&#39;Paul&#39;</span><span class="p">),</span>
         <span class="p">(</span><span class="s">&#39;beatles&#39;</span><span class="p">,</span><span class="s">&#39;George&#39;</span><span class="p">),</span>
         <span class="p">(</span><span class="s">&#39;beatles&#39;</span><span class="p">,</span><span class="s">&#39;Ringo&#39;</span><span class="p">)]</span>

<span class="k">class</span> <span class="nc">MyForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
    <span class="n">my_choices</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">ChoiceField</span><span class="p">(</span><span class="n">choices</span><span class="o">=</span><span class="n">CHOICES</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">RadioSelect</span><span class="p">())</span>
</pre></div>
</td></tr></table>

<p>Renderizando esse formulário temos um conjunto de <em>radio buttons</em>. Se não selecionarmos
nenhum deles e submetermos o formulário o <em>QueryDict</em> de <em>request.POST</em> é vazio, sendo
avaliado como <em>False</em> fazendo com que eles seja instanciado com o parâmetro <em>None</em> que nunca
será válido por ser <a href="https://docs.djangoproject.com/en/dev/ref/forms/api/#bound-and-unbound-forms">unbound</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Como eu testo formulários no Django</title>
      <link>http://rennerocha.com/2013/01/como-eu-testo-formularios-no-django</link>
      <pubDate>Wed, 30 Jan 2013 12:22:00 BRST</pubDate>
      <category><![CDATA[Computação]]></category>
      <guid>http://rennerocha.com/2013/01/como-eu-testo-formularios-no-django</guid>
      <description>Como eu testo formulários no Django</description>
      <content:encoded><![CDATA[<p>Uma das primeiras dúvidas de quem está começando a desenvolver aplicações em Django e quer
ter uma boa cobertura de testes é saber que tipo de testes devem ser escritos.</p>
<p>A <a href="https://docs.djangoproject.com/en/dev/topics/testing/">documentação do Django</a> sobre testes
é superficial, apresentando diversas ferramentas que podem ser utilizadas
para escrevermos os nossos testes unitários com exemplos muito simples que
ajudam pouco a saber o que, quando e como testar as partes da aplicação.</p>
<p>A <a href="https://docs.djangoproject.com/en/dev/topics/forms/">biblioteca de manipulação de formulários</a>
é uma das mais utilizadas do framework e os formulários criados possuem com muita freqüência
uma grande quantidade de regras de negócios e validações que <strong>devem</strong> ser testadas.</p>
<p>Como na maioria das vezes utilizamos o formulário dentro de uma view, uma abordagem
comum de testes é utilizar o
<a href="https://docs.djangoproject.com/en/dev/topics/testing/overview/#module-django.test.client">cliente de testes</a>
do Django e fazer requisições POST na view que o utiliza passando um dicionário com os dados
de preenchimento dele.</p>
<p>Por exemplo, temos um formulário que recebe informações de um endereço:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># forms.py</span>
<span class="k">class</span> <span class="nc">AddressForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
    <span class="n">street</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">32</span><span class="p">)</span>
    <span class="n">number</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
    <span class="n">complement</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
    <span class="n">city</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<p>O padrão mais comum de usar esse formulário é através de uma view que recebe os
dados via POST, verifica se o formulário está válido e o salva caso esteja válido
ou retorna uma lista de erros no caso contrário:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># views.py</span>
<span class="k">def</span> <span class="nf">add_address</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s">&#39;POST&#39;</span><span class="p">:</span>
        <span class="n">form</span> <span class="o">=</span> <span class="n">AddressForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
            <span class="n">address</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="s">&#39;/success/&#39;</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">form</span> <span class="o">=</span> <span class="n">AddressForm</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">render_to_response</span><span class="p">(</span><span class="s">&#39;new_address.html&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;form&#39;</span><span class="p">:</span> <span class="n">form</span><span class="p">})</span>
</pre></div>
</td></tr></table>

<p>Podemos testar esse formulário indiretamente, fazendo requisições à view add_address passando
como parâmetros POST as informações desejadas e verificando o conteúdo da resposta à 
requisição.</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># tests.py</span>
<span class="k">class</span> <span class="nc">AddressView</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">test_city_is_required</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">password</span><span class="p">)</span>

<span class="n">invalid_data</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;street&#39;</span><span class="p">:</span> <span class="s">&#39;Baker Street&#39;</span><span class="p">,</span>
                        <span class="s">&#39;number&#39;</span><span class="p">:</span> <span class="s">&#39;123&#39;</span><span class="p">,</span>
                        <span class="s">&#39;complement&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span><span class="p">})</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s">&#39;/add_address/&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">invalid_data</span><span class="p">)</span>

<span class="c"># Verificamos se existe um formulário no nosso retorno</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertTrue</span><span class="p">(</span><span class="s">&#39;form&#39;</span> <span class="ow">in</span> <span class="n">responsexxi</span><span class="o">.</span><span class="n">context</span><span class="p">)</span>

<span class="n">form</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s">&#39;form&#39;</span><span class="p">]</span>

<span class="c"># Verificamos se no formulário retornado</span>
        <span class="c"># temos o erro desejado</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">errors</span><span class="p">[</span><span class="s">&#39;city&#39;</span><span class="p">],</span>
                         <span class="p">[</span><span class="s">u&quot;This field is required.&quot;</span><span class="p">])</span>
</pre></div>
</td></tr></table>

<p>Porém neste caso não estamos testando realmente o formulário e sim sua integração
junto a view. Caso o formulário seja utilizado de outra maneira (em outra view por
exemplo), não temos como garantir que ele continuará funcionando corretamente.</p>
<p>Por exemplo, ao invés de fazer o teste acima passar modificando o formulário (colocando <em>required=True</em>
no campo <em>city</em> do formulário), podemos fazer essa validação direto na view. O teste passa, mas
se utilizarmos este formulário em outra view não teremos essa validação.</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># views.py</span>
<span class="k">def</span> <span class="nf">add</span> <span class="n">address</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s">&#39;POST&#39;</span><span class="p">:</span>
        <span class="n">form</span> <span class="o">=</span> <span class="n">AddressForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s">&#39;city&#39;</span><span class="p">]:</span>
            <span class="n">form</span><span class="o">.</span><span class="n">errors</span><span class="p">[</span><span class="s">&#39;city&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;This field is required.&#39;</span><span class="p">,</span> <span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
                <span class="n">address</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
                <span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="s">&#39;/success/&#39;</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">form</span> <span class="o">=</span> <span class="n">AddressForm</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">render_to_response</span><span class="p">(</span><span class="s">&#39;new_address.html&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;form&#39;</span><span class="p">:</span> <span class="n">form</span><span class="p">})</span>
</pre></div>
</td></tr></table>

<p><strong>Sim, eu sei que essa é uma maneira pouco usual de resolver este problema. O ponto que quero levantar é que 
dependendo do que estamos testando, o código que faz o teste passar não precisa necessariamente
estar dentro da classe de formulário.</strong></p>
<p>Porém, como o formulário é uma classe como qualquer outra, podemos testá-la diretamente
instanciando-a, preenchendo seus campos e chamando seus métodos de validação e de armazenamento
diretamente, verificando então sua saída.</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># tests_forms.py</span>
<span class="k">class</span> <span class="nc">AddressFormTestCase</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">test_city_is_required</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">invalid_form</span> <span class="o">=</span> <span class="n">AddressForm</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;street&#39;</span><span class="p">:</span> <span class="s">&#39;Baker Street&#39;</span><span class="p">,</span>
                                         <span class="s">&#39;number&#39;</span><span class="p">:</span> <span class="s">&#39;221B&#39;</span><span class="p">,</span>
                                         <span class="s">&#39;complement&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span><span class="p">})</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertFalse</span><span class="p">(</span><span class="n">invalid_form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">())</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">invalid_form</span><span class="o">.</span><span class="n">errors</span><span class="p">[</span><span class="s">&#39;city&#39;</span><span class="p">],</span>
                         <span class="p">[</span><span class="s">u&quot;This field is required.&quot;</span><span class="p">])</span>

<span class="n">valid_form</span> <span class="o">=</span> <span class="n">AddressForm</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;street&#39;</span><span class="p">:</span> <span class="s">&#39;Baker Street&#39;</span><span class="p">,</span>
                                       <span class="s">&#39;number&#39;</span><span class="p">:</span> <span class="s">&#39;221B&#39;</span><span class="p">,</span>
                                       <span class="s">&#39;complement&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span><span class="p">,</span>
                                       <span class="s">&#39;city&#39;</span><span class="p">:</span> <span class="s">&#39;London&#39;</span><span class="p">})</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertTrue</span><span class="p">(</span><span class="n">valid_form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">())</span>

<span class="c"># (...) Outros testes do formulário</span>
</pre></div>
</td></tr></table>

<p>Fazendo este teste passar:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># forms.py</span>
<span class="k">class</span> <span class="nc">AddressForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
    <span class="n">street</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">32</span><span class="p">)</span>
    <span class="n">number</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
    <span class="n">complement</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
    <span class="n">city</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<p>Como eu estou garantindo que o comportamento do formulário está correto, quando eu for testar
alguma view que o utilize, eu não preciso de muitos testes. Na view de exemplo, eu preciso 
fazer basicamente testes para essas condições:</p>
<ul>
<li>Testar a renderização do formulário vazio</li>
<li>Testar a submissão de um formulário preenchido com dados válidos</li>
<li>Testar a submissão de um formulário preenchido com dados inválidos</li>
</ul>
<p>Assim consigo isolar ainda mais meus testes facilitando a reutilização
de partes da minha aplicação.</p>]]></content:encoded>
    </item>
    <item>
      <title>Criptografia: Cifras de Substituição</title>
      <link>http://rennerocha.com/2013/01/criptografia--cifras-de-substituicao</link>
      <pubDate>Mon, 21 Jan 2013 21:38:00 BRST</pubDate>
      <category><![CDATA[Computação]]></category>
      <guid>http://rennerocha.com/2013/01/criptografia--cifras-de-substituicao</guid>
      <description>Criptografia: Cifras de Substituição</description>
      <content:encoded><![CDATA[<p>Uma cifra de substituição é um método de <strong>criptografia</strong> onde unidades de texto são substituídas
por unidades de texto-cifrados seguindo um sistema regular e pré-determinado. Essas unidades de texto
podem ser letras, números, pares de letras, triplas de letras ou uma combinação de todos.
Para recuperar uma mensagem cifrada, o receptor deve apenas fazer a substituição inversa.</p>
<h4>Cifras de Substituição Simples</h4>
<p>Este tipo de cifra faz o mapeamento entre uma letra do alfabeto com outra, definido por alguma regra pré-estabelecida.
Este mapeamento cria um <strong>alfabeto de substituição</strong> que é utilizado tanto para encriptar quanto para desencriptar uma
mensagem. Considerando as 26 letras do alfabeto, é possível gerar 26! (26 fatorial) <strong>alfabetos de substituição</strong>
distintos.</p>
<p>Apesar do número grande de <strong>alfabetos de substituição</strong>, estas cifras são facilmente quebradas
através de <a href="http://pt.wikipedia.org/wiki/An%C3%A1lise_de_frequ%C3%AAncia">análise de freqüência</a> da ocorrência de
letras em um idioma. Com um conjunto suficientemente grande de mensagens cifradas podemos
relacionar o percentual de ocorrência das letras-cifradas com o percentual das letras no idioma do
texto-cifrado. Com isso um conjunto de combinações mais viáveis pode ser descoberto e avaliado.</p>
<h4>Exemplos de Cifras de Substituição Simples</h4>
<p>Uma das mais conhecidas cifras de substituição simples é a <strong><a href="http://en.wikipedia.org/wiki/Caesar_cipher">Cifra de César</a></strong>
utilizada pelo imperador romano <a href="http://en.wikipedia.org/wiki/Julius_Caesar">Julius Caesar</a>. Nesta cifra um valor de
deslocamento é definido, então cada letra do texto é substituída pela letra do alfabeto referente a esse
deslocamento. Por exemplo, com um deslocamento de <strong>3</strong>, a letra <strong>A</strong> é substituída pela letra <strong>D</strong>,
<strong>B</strong> se torna <strong>E</strong> e assim sucessivamente. As letras do final do alfabeto, são substituídas pelas primeiras: <strong>X</strong> se torna
<strong>A</strong>, <strong>Y</strong> se torna <strong>B</strong> e <strong>Z</strong> se torna <strong>C</strong>.</p>
<p>Uma variação desta cifra é a <a href="http://en.wikipedia.org/wiki/ROT13">ROT13</a> que é uma <strong>Cifra de César</strong> com deslocamento
13. A vantagem de usar esse valor para o deslocamento é que, para encriptar e para desencriptar uma mensagem, podemos
utilizar o mesmo algoritmo.</p>
<p>Para implementar uma cifra de substituição simples em <a href="http://python.org">Python</a> podemos utilizar as seguintes funções
do módulo <em><a href="http://docs.python.org/2/library/string.html#module-string">string</a></em> da biblioteca padrão:
<em><a href="http://docs.python.org/2/library/string.html#string.maketrans">maketrans</a></em> para criar uma tabela de substituição
e a função <em><a href="http://docs.python.org/2/library/string.html#string.translate">translate</a></em> para fazer a conversão.</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># Exemplo da Cifra de Cesar</span>
<span class="kn">import</span> <span class="nn">string</span>

<span class="k">def</span> <span class="nf">encrypt</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">shift</span><span class="p">):</span>
    <span class="n">original</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">ascii_uppercase</span>
    <span class="n">new</span> <span class="o">=</span> <span class="n">original</span><span class="p">[</span><span class="n">shift</span><span class="p">:]</span> <span class="o">+</span> <span class="n">original</span><span class="p">[:</span><span class="n">shift</span><span class="p">]</span>
    <span class="n">conversion_table</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">maketrans</span><span class="p">(</span><span class="n">original</span><span class="p">,</span> <span class="n">new</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">string</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="n">conversion_table</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="n">encrypted_message</span><span class="p">,</span> <span class="n">shift</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">encrypt</span><span class="p">(</span><span class="n">encrypted_message</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="o">-</span><span class="n">shift</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<p>Outro exemplo de cifra de substituição é a <strong>Cifra de Vigenère</strong> - uma variação da Cifra de César, descrita pela primeira vez em 1553 no livro
<a href="http://en.wikipedia.org/wiki/Giovan_Battista_Bellaso">La cifra del Sig. Giovan Battista Bellaso</a>. É uma cifra
simples de aprender e implementar.</p>
<p>Para encriptar uma mensagem, escolhemos uma palavra que será utilizada
como chave da encriptação. Cada letra desta palavra define um deslocamento
diferente que será usado na Cifra de César.</p>
<p>Por exemplo, se escolhermos a palavra CRIPTO para ser a chave de nossa cifra, temos os seguintes valores de deslocamentos: 3 18 9 20 15.</p>
<p>Queremos encriptar a seguinte frase:</p>
<p>TESTANDO A CIFRA DE VIGENERE</p>
<p>Para cada letra desta frase, usamos a Cifra de César com os deslocamentos
definidos pela palavra-chave ciclicamente:</p>
<pre>
T  E  S  T  A  N  D  O  A  C  I  F  R  A  D  E  V  I  G  E  N  E  R  E
3  18 9  20 15 3  18 9  20 15 3  18 9  20 15 3  18 9  20 15 3  18 9  20
-----------------------------------------------------------------------
V  V  A  I  T  B  F  F  I  R  B  T  T  R  L  T  O  W  I  V  V  T  K  S
</pre>

<p>A maior fraqueza desta cifra é a natureza repetitiva de sua chave. Se descobrimos corretamente o tamanho da letra, então o texto cifrado pode ser 
quebrado por análise de freqüência do mesmo modo que a cifra de César.</p>
<p>Exemplo de implementação:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="kn">import</span> <span class="nn">string</span>

<span class="k">def</span> <span class="nf">caesar_encrypt</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">shift</span><span class="p">):</span>
    <span class="n">original</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">ascii_uppercase</span>
    <span class="n">new</span> <span class="o">=</span> <span class="n">original</span><span class="p">[</span><span class="n">shift</span><span class="p">:]</span> <span class="o">+</span> <span class="n">original</span><span class="p">[:</span><span class="n">shift</span><span class="p">]</span>
    <span class="n">conversion_table</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">maketrans</span><span class="p">(</span><span class="n">original</span><span class="p">,</span> <span class="n">new</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">string</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="n">conversion_table</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">encrypt</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
    <span class="n">message_size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
    <span class="n">key_size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
    <span class="n">multiplier</span> <span class="o">=</span> <span class="p">(</span><span class="n">message_size</span> <span class="o">/</span> <span class="n">key_size</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">message_size</span> <span class="o">%</span> <span class="n">key_size</span><span class="p">)</span>
    <span class="n">shift_values</span> <span class="o">=</span> <span class="p">[</span><span class="nb">ord</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span> <span class="o">-</span> <span class="mi">65</span> <span class="k">for</span> <span class="n">letter</span> <span class="ow">in</span> <span class="n">key</span> <span class="o">*</span> <span class="n">multiplier</span><span class="p">]</span>
    <span class="k">return</span> <span class="s">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">caesar_encrypt</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">shift_values</span><span class="p">[</span><span class="n">index</span><span class="p">])</span> <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">letter</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">message</span><span class="p">)])</span>

<span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
    <span class="n">message_size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
    <span class="n">key_size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
    <span class="n">multiplier</span> <span class="o">=</span> <span class="p">(</span><span class="n">message_size</span> <span class="o">/</span> <span class="n">key_size</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">message_size</span> <span class="o">%</span> <span class="n">key_size</span><span class="p">)</span>
    <span class="n">shift_values</span> <span class="o">=</span> <span class="p">[</span><span class="nb">ord</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span> <span class="o">-</span> <span class="mi">65</span> <span class="k">for</span> <span class="n">letter</span> <span class="ow">in</span> <span class="n">key</span> <span class="o">*</span> <span class="n">multiplier</span><span class="p">]</span>
    <span class="k">return</span> <span class="s">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">caesar_encrypt</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="o">-</span><span class="n">shift_values</span><span class="p">[</span><span class="n">index</span><span class="p">])</span> <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">letter</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">message</span><span class="p">)])</span>
</pre></div>
</td></tr></table>]]></content:encoded>
    </item>
    <item>
      <title>DIY: Suporte para notebook com cano de PVC</title>
      <link>http://rennerocha.com/2012/12/diy--suporte-para-notebook-com-cano-de-pvc</link>
      <pubDate>Sun, 02 Dec 2012 19:21:38 BRST</pubDate>
      <category><![CDATA[DIY]]></category>
      <guid>http://rennerocha.com/2012/12/diy--suporte-para-notebook-com-cano-de-pvc</guid>
      <description>DIY: Suporte para notebook com cano de PVC</description>
      <content:encoded><![CDATA[<p>Um suporte para notebook é muito útil para quem trabalha o dia todo no computador
e quer mantê-lo em uma posição mais confortável com a tela na altura dos olhos.
Adicionando também um teclado e mouse externos de qualidade, temos um aumento grande
no conforto (pelo menos eu acho bem mais confortável trabalhar assim).</p>
<p>Existem diversas opções no mercado, custando a partir de R$30 (pesquisando no MercadoLivre),
mas como eu queria economizar encontrei alguns projetos de suportes feitos com canos de PVC e 
resolvi fazer o meu. Com menos de R$7 comprei os materiais necessários (cano e cotovelos), 
peguei emprestado um cortador de cano de PVC (você pode usar uma
uma <a href="http://www.copaautopecas.com.br/index.php?productID=974">serrinha amarela</a> no lugar, mas
dá um pouquinho mais de trabalho para cortar) e em menos de 30 minutos meu suporte estava pronto!</p>
<h4>Materiais Necessários</h4>
<ul>
<li>1 cano de PVC de 20mm</li>
<li>10 cotovelos de 90 graus</li>
</ul>
<h4>Como fazer</h4>
<p>Corte o cano de PVC com as seguintes medidas:</p>
<ul>
<li>2 partes de 29cm</li>
<li>2 partes de 25cm</li>
<li>2 partes de 10cm</li>
<li>2 partes de 5cm</li>
<li>2 partes de 2.5cm</li>
</ul>
<p>Eu calculei essas medidas com base no meu notebook que tem 38cm x 26cm.
Se seu notebook for menor (ou maior), você precisa adaptar as medidas. Também cortei
ele de modo a parte mais alta do suporte ficar a cerca de 10cm de altura.</p>
<p><img alt="Materiais para montagem" src="/media/photos/000017_materiais.jpg" /></p>
<h4>Montagem</h4>
<p>A montagem é bem simples. Observando a imagem deve ficar fácil de entender onde cada
peça se encaixa. Prenda os canos bem forte dentro dos cotovelos. Não é necessário usar 
cola, os canos se fixam muito bem sozinhos.</p>
<p><img alt="Suporte montado - 1" src="/media/photos/000017_montado_vazio.jpg" />
<img alt="Suporte montado - 2" src="/media/photos/000017_montado_com_notebook.jpg" /></p>
<p>Cheguei a testar em um pedaço de cano que sobrou a pintura usando tinta spray.
Funciona, mas tem que tomar cuidado de não passar tinta demais, senão forma bolhas
e a tinta escorre. O melhor é passar bem rápido o spray uma vez, deixando a tinta secar
e repetir esse processo até conseguir que a cor fique uniforme.</p>
<p>Mas no fim resolvi deixar ele na cor "natural" de cano de PVC :-) Talvez um próximo
(já fizeram sugestões de como fazer ele ter ajuste de altura) eu faça ele colorido.</p>]]></content:encoded>
    </item>
    <item>
      <title>Ambientes Python isolados na sua conta do Webfaction</title>
      <link>http://rennerocha.com/2012/11/virtualenv-no-webfaction</link>
      <pubDate>Mon, 19 Nov 2012 19:35:02 BRST</pubDate>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Webfaction]]></category>
      <guid>http://rennerocha.com/2012/11/virtualenv-no-webfaction</guid>
      <description>Ambientes Python isolados na sua conta do Webfaction</description>
      <content:encoded><![CDATA[<p>O <a href="http://www.webfaction.com/?affiliate=rennerocha">Webfaction</a> é um dos serviços de 
hospedagem mais amigáveis para aplicações <a href="http://python.org">Python</a> que conheço.
Com preços convidativos, um suporte técnico de alta qualidade e grande flexibilidade
na instalação e configuração de diversas ferramentas, é minha primeira escolha para hospedar
minhas aplicações.</p>
<p>Como temos a liberdade de utilizar diferentes versões de frameworks e pacotes, é fundamental 
separá-los de alguma maneira para evitar conflitos. A melhor maneira para fazer isso em projetos
<a href="http://python.org">Python</a> é utilizar o <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a>.</p>
<p>Como o próprio nome indica, o <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> cria ambientes 
virtuais isolados de modo que, se você instalar um pacote em um deles, ele não irá afetar nenhum 
outro. Basicamente ele altera o <a href="http://docs.python.org/2/library/sys.html#sys.path">sys.path</a>
que define os caminhos onde os módulos são buscados pelo interpretador.</p>
<p>Para ajudar no gerenciamento desses ambientes, temos o 
<a href="http://www.doughellmann.com/projects/virtualenvwrapper/">virtualenvwrapper</a>, um conjunto de extensões 
para o <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> que facilita a criação, utilização e exclusão
de ambientes. Iremos instalar as duas ferramentas no ambiente do <a href="http://www.webfaction.com/?affiliate=rennerocha">Webfaction</a>.</p>
<h4>Definindo a versão padrão do Python</h4>
<p>Nos servidores do <a href="http://www.webfaction.com/?affiliate=rennerocha">Webfaction</a>, a versão padrão do 
<a href="http://pythong.org">Python</a> em linha de comando é a 2.6. Para utilizar a versão 2.7 é necessário
criar um <em>alias</em> na sua conta:</p>
<ul>
<li>Abra uma <a href="http://docs.webfaction.com/user-guide/access.html">sessão SSH</a> na sua conta</li>
<li>Edite o arquivo <em>$HOME/.bashrc</em> e acrescente a seguinte linha no final do arquivo:</li>
</ul>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="nb">alias </span><span class="nv">python</span><span class="o">=</span>python2.7
</pre></div>
</td></tr></table>

<ul>
<li>Recarregue o arquivo com o comando: <em>source $HOME/.bashrc</em></li>
<li>A partir de agora, todas as sessões SSH usarão essa versão do Python como padrão</li>
</ul>
<h4>Instalando</h4>
<p>Instalar um pacote Python nos servidores do Webfaction é muito fácil. O módulo
<a href="http://packages.python.org/distribute/easy_install.html">easy_install</a> está instalado
para todos os usuários:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="pygments_default"><pre>easy_install-2.7 pip
pip install virtualenv virtualenvwrapper
</pre></div>
</td></tr></table>

<h4>Configurando</h4>
<p>Para completar a instalação, edite novamente o arquivo <em>$HOME/.bashrc</em> e adicione
as seguintes configurações:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="c"># set the workonhome and virtualenvwrapper_python</span>
<span class="nb">export </span><span class="nv">WORKON_HOME</span><span class="o">=</span><span class="nv">$HOME</span>/.virtualenvs
<span class="nb">export </span><span class="nv">VIRTUALENVWRAPPER_PYTHON</span><span class="o">=</span>/usr/local/bin/python2.7
<span class="c"># add the virtualenvwrapper hook</span>
<span class="nb">source</span> <span class="nv">$HOME</span>/bin/virtualenvwrapper.sh
</pre></div>
</td></tr></table>

<p>Pronto! Você já tem o necessário para criar ambientes virtuais na sua conta.</p>]]></content:encoded>
    </item>
    <item>
      <title>Referências para estudar TDD</title>
      <link>http://rennerocha.com/2012/10/referencias-para-estudar-tdd</link>
      <pubDate>Thu, 25 Oct 2012 21:51:02 BRST</pubDate>
      <category><![CDATA[TDD]]></category>
      <guid>http://rennerocha.com/2012/10/referencias-para-estudar-tdd</guid>
      <description>Referências para estudar TDD</description>
      <content:encoded><![CDATA[<p><em>Test-Driven Development</em> (TDD) é uma técnica para desenvolvimento de software que define um processo
simples que repetido auxilia o desenvolvedor fornecendo um <em>feedback</em> rápido de decisões de <em>design</em> no
código, encorajando soluções simples e, por fazer com que praticamente todo o código esteja coberto
por testes, permite que o desenvolvedor tenha confiança para realizar mudanças no código 
pois é mais difícil alterar uma parte do sistema sem ter um retorno rápido se o trecho de 
código alterado tem impacto em outras partes do sistema.</p>
<p>O ciclo do TDD é muito fácil de ser ensinado. Temos apenas um pequeno conjunto de passos:</p>
<ol>
<li>Adicione um teste simples de uma pequena parte da funcionalidade que você quer desenvolver. 
Este teste irá falhar, pois ainda a funcionalidade não foi implementada.</li>
<li>Escrever o código mais simples possível que faça este teste passar (e não faça nenhum teste anterior
falhar).</li>
<li>Refatorar o código resultante (código de produção e código de teste).</li>
<li>Reiniciar o ciclo com um novo teste.</li>
</ol>
<p><img alt="Fluxograma TDD" src="/media/img/tdd_cycle.jpg" /></p>
<p>Apesar de parecer muito simples, é necessário muito cuidado e experiência para saber quais testes escrever,
o que significa escrever o código mais simples possível (simples é diferente de mal-feito) e principalmente
não esquecer de fazer o passo de refatoração.</p>
<p>Para realmente aprender TDD é necessário muito estudo com a leitura de livros, participação em Coding Dojos
e principalmente escrever o máximo de código possível. A seguir eu listo alguns livros e sites que podem ser
usados como referência para quem está começando ou quer aprofundar mais o estudo desta técnica.</p>
<h4>Livros</h4>
<p><strong><a href="http://www.amazon.com/Test-Driven-Development-Addison-Wesley-Signature/dp/0321146530/">Test Driven Development: By Example</a></strong></p>
<p><em>Autor</em>: Kent Beck</p>
<p>Principal referência para quem quer começar a trabalhar com TDD. O livro é dividido em três partes. Nas duas
primeiras dois projetos são desenvolvidos ilustrando várias técnicas que podem ser facilmente usadas 
para melhorar a qualidade do projeto do seu código. Na terceira parte, padrões de organização e definição de testes 
e refatoração de código utilizados nas primeiras partes do livro são compilados servindo como uma ótima 
referência para leitura posterior.</p>
<p><strong><a href="http://www.amazon.com/dp/0321503627/">Growing Object-Oriented Software, Guided by Tests</a></strong></p>
<p><em>Autores</em>: Steve Freeman, Nat Pryce</p>
<p>Considerado o livro-texto da escola londrina de TDD (a escola clássica é descrita no livro do Kent Beck).
Os autores descrevem o processo que eles utilizam, os princípios que eles se guiam e algumas ferramentas utilizadas 
para fazer com que os testes guiem a estrutura do código orientado a objetos, e com o uso de objetos
Mock descobrir e descrever relações e interações entre esses objetos. Para saber mais sobre a diferença entre a
escola Londrina e a escola Clássica de TDD, <a href="http://codemanship.co.uk/parlezuml/blog/?postid=987">leia este artigo</a>.</p>
<p><strong><a href="http://www.casadocodigo.com.br/products/livro-tdd">Test-Driven Development: Teste e Design no Mundo Real</a></strong></p>
<p><em>Autor</em>: Mauricio Aniche</p>
<p>O mercado brasileiro tem poucas opções de material técnico de qualidade em português mas a editora
<strong><a href="http://www.casadocodigo.com.br/">A Casa do Código</a></strong> entrou no mercado recentemente com muitos 
títulos interessantes, entre eles esse livro escrito por um dos profissionais que é referência em 
TDD no país (este foi o tema de sua tese de mestrado na USP). Ainda não li o livro, mas já participei 
de um Workshop com o autor e acompanho o seu blog. Conhecendo o seu trabalho, fico a vontade de indicar 
este livro.</p>
<p><strong><a href="http://www.amazon.com/Lean-Agile-Acceptance-Test-Driven-Development-Collaboration/dp/0321714083/">Lean-Agile Acceptance Test-Driven Development: Better Software Through Collaboration</a></strong></p>
<p><em>Autor</em>: Ken Pugh</p>
<p>Este livro apresenta as idéias de ATDD (Acceptance Test-Driven Development), que incentiva a colaboração
de toda a equipe do projeto (clientes, desenvolvedores e testadores) na definição de critérios claros de aceitação
dos requisitos de um sistema. Apesar de não tratar de técnicas de desenvolvimento de código, é uma abordagem
eficiente de definir o que precisa ser desenvolvido facilitando a utilização do TDD melhorando significativamente
a qualidade do software e a produtividade dos desenvolvedores.</p>
<p><strong><a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/">Refactoring: Improving the Design of Existing Code</a></strong></p>
<p><em>Autores</em>: Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Robert</p>
<p>O terceiro passo do TDD é a refatoração, porém ele é freqüentemente esquecido e negligenciado. A ênfase
dos programadores fica sendo escrever testes falhando, corrigindo-os o mais rapidamente possível para
continuar escrevendo novos testes. Mas a <strong>refatoração</strong> é uma parte fundamental do processo. Este livro
apresenta uma discussão dos princípios de refatoração com vários exemplos de como utilizá-los.</p>
<h4>Na Internet</h4>
<p><strong><a href="http://sourcemaking.com/refactoring">Refactoring</a></strong>
Uma referência com dezenas de exemplos de como utilizar técnicas de refatoração de código. Deve estar na 
lista de favoritos de qualquer desenvolvedor.</p>
<p><strong><a href="http://www.aniche.com.br/tag/tdd/">Blog do Mauricio Aniche</a></strong>
Alguns artigos sobre TDD escritos por um dos principais pesquisadores de TDD do Brasil.</p>
<p><strong><a href="http://www.testingminded.com/2010/04/top-100-software-testing-blogs.html/">Top 100 Software Testing Blogs</a></strong>
Uma lista com links para 100 blogs sobre teste de software.</p>
<p><strong><a href="http://www.cleancoders.com/">Clean Coders</a></strong>
Uma série de vídeos feitos por Robert Martin (mais conhecido como <em>Uncle Bob</em>) sobre vários assuntos fundamentais
para quem quer programar melhor.</p>]]></content:encoded>
    </item>
    <item>
      <title>Primeiro Coding Dojo no Laboratório Hacker de Campinas</title>
      <link>http://rennerocha.com/2012/10/09/primeiro-coding-dojo-no-laboratório-hacker-de-campinas</link>
      <pubDate>Tue, 09 Oct 2012 22:04:00 BRT</pubDate>
      <category><![CDATA[Dojo]]></category>
      <category><![CDATA[LHC]]></category>
      <guid isPermaLink="true">http://rennerocha.com/2012/10/09/primeiro-coding-dojo-no-laboratório-hacker-de-campinas</guid>
      <description>Primeiro Coding Dojo no Laboratório Hacker de Campinas</description>
      <content:encoded><![CDATA[<p>No último sábado (6 de outubro) aconteceu o primeiro Coding Dojo no
<a href="http://lhc.net.br/">Laboratório Hacker de Campinas</a>. Mesmo começando
um pouco atrasados, tivemos um bom número de participantes (cinco)
que tiveram disposição de acordar cedo em um sábado.</p>
<p>Para quem nunca participou de um <a href="http://codingdojo.org/">Coding Dojo</a>, 
segue uma explicação rápida:</p>
<blockquote>
<p>Um <strong>Coding Dojo</strong> é um encontro onde um grupo de programadores se reúne
para praticar suas habilidades de programação resolvendo um desafio simples, mas
utilizando ao máximo boas práticas (como programação em par, e TDD).</p>
</blockquote>
<p>Existem vários grupos de Dojo em várias cidades e países. Aqui em Campinas, temos
uma <a href="https://groups.google.com/forum/?fromgroups=#!forum/dojo-campinas">lista de discussão</a> 
onde os encontros são marcados e divulgados. Ainda não temos na cidade um calendário 
regular de encontros como existem em outras cidades (<a href="http://dojorio.org/">Rio de Janeiro</a> 
por exemplo), mas existem conversas para organizar Dojos regularmente em empresas da 
cidade (novamente, entre na lista para saber mais).</p>
<h4>O problema</h4>
<p>Neste primeiro Dojo, escolhemos um problema que inicialmente parecia simples.
Teríamos que implementar as regras básicas de uma
<a href="http://www.dojopuzzles.com/problemas/exibe/partida-de-tenis/">partida de tênis</a>.</p>
<p><img alt="Dojo LHC - 1" src="/media/photos/foto_dojo1.jpg" /></p>
<p>A linguagem escolhida (democraticamente pelo dono do notebook) para resolver o problema foi 
<a href="http://python.org">Python</a>. Começamos a implementar a pontuação de uma partida de tênis 
simples (dois jogadores). Não conseguimos terminar, pois ficamos discutindo qual a melhor 
maneira de indicar quando a partida estava empatada ou quando um jogador estava com 
vantagem e já estava na hora do almoço.</p>
<p><img alt="Dojo LHC - 2" src="/media/photos/foto_dojo2.jpg" /></p>
<p>O código (parcialmente) desenvolvido pode ser visualizado
<a href="https://github.com/lhc/dojo-lhc/tree/master/dojo-20121006">aqui</a>. Quem quiser
continuar o desenvolvimento, faça um fork e depois compartilhe aqui :-)</p>
<h4>Próximos Encontros</h4>
<p>Como muitas pessoas se interessaram pela dinâmica do Dojo, esses
encontros irão se tornar parte dos <strong>evento regulares</strong> do LHC. A princípio
<a href="/sobre">eu</a> estarei organizando esses encontros.</p>
<p>Todo <strong>primeiro sábado do mês</strong>, das 10h às 12h teremos uma sessão
de Dojo. O próximo já está agendado! <del>Será no dia <strong>3 de novembro</strong>.</del> <strong>ATUALIZAÇÃO: Tendo em vista o feriado do dia 2 de novembro, este mês, excepcionalmente o Dojo será no dia 10 de novembro</strong>. Não é necessário se inscrever para participar, apenas aparecer!</p>]]></content:encoded>
    </item>
    <item>
      <title>Caipira Ágil</title>
      <link>http://rennerocha.com/2012/08/15/caipira-agil/</link>
      <pubDate>Wed, 15 Aug 2012 21:20:00 BRT</pubDate>
      <category><![CDATA[agile]]></category>
      <guid>http://rennerocha.com/2012/08/15/caipira-agil/</guid>
      <description>Caipira Ágil</description>
      <content:encoded><![CDATA[<p>No próximo sábado, dia 18 de agosto, ocorrerá a segunda edição do <em><a href="http://caipiraagil.com/">Caipira Ágil</a></em>, evento que reunirá a comunidade ágil da região de Campinas. A edição passada teve 150 inscritos e hoje o número de inscritos já foi superado chegando a mais de 200 inscritos. Mas ainda é possível inscrever-se <em><a href="http://caipiraagil.com/inscricoes">aqui</a></em>!</p>
<p>Este ano, o <em>Caipira Ágil</em> faz parte também da grade da <em><a href="http://secomp.com.br">Semana Acadêmica de Computação</a></em>, facilitando com que estudantes possam participar, aumentando o público do evento.</p>
<h2>Programação</h2>
<p>Dividido em quatro trilhas simultâneas, teremos:</p>
<ul>
<li>4 Coding Dojos em diferentes linguagens (Scala, Java, Ruby e Lua);</li>
<li>15 <a href="http://caipiraagil.com/talks">Lightning Talks</a> dos mais variados assuntos;</li>
<li>9 Workshops com profissionais que são referência nacional em desenvolvimento ágil;</li>
<li>Open-Space onde oficializamos a <em>conversa de corredos</em> dos eventos.</li>
</ul>
<p>Saiba mais <a href="http://caipiraagil.com/programacao">detalhes</a> da programação no site do evento.</p>
<p>E como não poderíamos deixar passar, o coffe-break do <em>Caipira Ágil</em> promete ser ainda melhor do que o do ano passado :-)</p>]]></content:encoded>
    </item>
    <item>
      <title>Manipulando arquivo INI com Python</title>
      <link>http://rennerocha.com/2012/01/05/manipulando-arquivo-ini-com-python</link>
      <pubDate>Thu, 05 Jan 2012 13:37:00 BRST</pubDate>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[lhc]]></category>
      <guid isPermaLink="true">http://rennerocha.com/2012/01/05/manipulando-arquivo-ini-com-python</guid>
      <description>Manipulando arquivo INI com Python</description>
      <content:encoded><![CDATA[<p>O formato de arquivos INI é um padrão para armazenar informações de configuração de aplicativos e 
alguns sistemas operacionais (versões antigas do MS-Windows utilizavam esse padrão manter algumas de 
suas configurações). Um arquivo INI é simplesmente um arquivo de texto com uma estrutura bem definida 
composta basicamente por <em>seções</em> e <em>opções</em>.</p>
<p>Um exemplo de aplicação que utiliza este formato é o <strong><a href="http://trac.edgewall.org/" title="Trac">Trac</a></strong>, ferramenta
para controle de mudanças em projetos de software. Cada projeto do <strong><a href="http://trac.edgewall.org/" title="Trac">Trac</a></strong> 
criado possui o arquivo <em>trac.ini</em> contendo a maioria das configurações necessárias para o seu funcionamento. 
Por ser altamente customizável, é interessante ter a possibilidade de alterar esses valores de 
configuração de uma maneira automática.</p>
<h2>Criando um arquivo de configuração</h2>
<p>Em Python, em sua biblioteca padrão, existe o módulo <strong><a href="http://docs.python.org/library/configparser.html" title="ConfigParser">ConfigParser</a></strong> 
(renomeado para <em>configparser</em> no Python 3.0) que, através da classe <em>ConfigParser</em> fornece um conjunto de métodos para 
trabalhar com arquivos desse tipo.</p>
<p>Criar um arquivo de configuração é simples. Precisamos de uma instância da classe <em>ConfigParser</em></p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="kn">import</span> <span class="nn">ConfigParser</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">ConfigParser</span><span class="o">.</span><span class="n">ConfigParser</span><span class="p">()</span>
</pre></div>
</td></tr></table>

<p>Essa instância (<em>config</em>), ainda não possui nenhuma informação (um arquivo vazio caso seja armazenada agora), 
então precisamos incluir <em>seções</em> e <em>opções</em> com valores nela. Vamos incluir duas seções: <em>section1</em> e <em>section2</em> 
utilizando o método 
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.add_section" title="add_section">add_section</a></strong>:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="n">config</span><span class="o">.</span><span class="n">add_section</span><span class="p">(</span><span class="s">&#39;section1&#39;</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_section</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<p>Em cada seção adicionada, podemos definir opções com seus respectivos valores utilizando o método
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.set" title="set">set</a></strong>. O primeiro 
parâmetro deste método é a seção onde o valor será incluído, o segundo parâmetro é a opção e o terceiro o valor desejado.</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="n">config</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s">&#39;section1&#39;</span><span class="p">,</span> <span class="s">&#39;opcao1&#39;</span><span class="p">,</span> <span class="s">&#39;valor1&#39;</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s">&#39;section1&#39;</span><span class="p">,</span> <span class="s">&#39;opcao2&#39;</span><span class="p">,</span> <span class="s">&#39;valor2&#39;</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">,</span> <span class="s">&#39;outraopcao&#39;</span><span class="p">,</span> <span class="s">&#39;valor&#39;</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">,</span> <span class="s">&#39;numerico&#39;</span><span class="p">,</span> <span class="s">&#39;123&#39;</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<p>Após essas operações, teríamos um arquivo de configuração desta maneira:</p>
<blockquote>
<p>[section1]  <br />
opcao1 = valor1  <br />
opcao2 = valor2 <br />
</p>
<p>[section2] <br />
outraopcao = valor <br />
numerico = 123 <br />
</p>
</blockquote>
<h2>Abrindo um arquivo de configuração já existente</h2>
<p>Até agora estamos criando um novo arquivo de configuração, porém normalmente o que queremos fazer é alterar 
as configurações de um arquivo já existente. Se tivermos um arquivo chamado <em>config.ini</em>, utilizamos o método 
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.read" title="read">read</a></strong> indicando
como argumento, uma lista com o nome dos arquivos que devem ser lidos (nesse caso, apenas um):</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="kn">import</span> <span class="nn">ConfigParser</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">ConfigParser</span><span class="o">.</span><span class="n">ConfigParser</span><span class="p">()</span>
<span class="n">config</span><span class="o">.</span><span class="n">read</span><span class="p">([</span><span class="s">&#39;config.ini&#39;</span><span class="p">])</span>
</pre></div>
</td></tr></table>

<p>Feito isso, podemos manipular essa instância de <em>ConfigParser</em> da mesma maneira como já fizemos anteriormente.</p>
<h2>Lendo seções e valores</h2>
<p>Após efetuar a leitura de um arquivo de configuração, queremos ser capazes de obter as informações 
armazenadas nele. Por exemplo, se eu quiser saber todas as seções existentes do arquivo <em>config.ini</em> 
que estamos utilizando como exemplo:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">c</span><span class="o">.</span><span class="n">sections</span><span class="p">()</span> <span class="c"># Retorna uma lista com todas as seções existentes</span>
<span class="p">[</span><span class="s">&#39;section1&#39;</span><span class="p">,</span> <span class="s">&#39;section2&#39;</span><span class="p">]</span>
</pre></div>
</td></tr></table>

<p>Sabendo o nome da seção, podemos obter todos as suas opções e valores associados:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="o">&gt;&gt;&gt;</span> <span class="c"># Retorna uma lista de tuplas (nome, valor) para cada opção na seção informada</span>
<span class="o">...</span> <span class="n">c</span><span class="o">.</span><span class="n">items</span><span class="p">(</span><span class="s">&#39;section1&#39;</span><span class="p">)</span>
<span class="p">[(</span><span class="s">&#39;opcao1&#39;</span><span class="p">,</span> <span class="s">&#39;valor1&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;opcao2&#39;</span><span class="p">,</span> <span class="s">&#39;valor2&#39;</span><span class="p">)]</span>
</pre></div>
</td></tr></table>

<p>Se quisermos o valor de uma opção específica:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="o">&gt;&gt;&gt;</span> <span class="c"># Retorna o valor da opcao2 na section1</span>
<span class="o">...</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;section1&#39;</span><span class="p">,</span> <span class="s">&#39;opcao2&#39;</span><span class="p">)</span>
<span class="s">&#39;valor2&#39;</span>
</pre></div>
</td></tr></table>

<p>O método <strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.get" title="get">get</a></strong> sempre retorna 
uma string. Caso saibamos com antecedência o tipo do valor que estamos obtendo, podemos usar métodos específicos: 
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.getint" title="getint">getint</a></strong>, 
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.getfloat" title="getfloat">getfloat</a></strong> e 
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.getboolean" title="getboolean">getboolean</a></strong>.</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">valor</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">,</span> <span class="s">&#39;numerico&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">type</span><span class="p">(</span><span class="n">valor</span><span class="p">)</span>
<span class="o">&lt;</span><span class="nb">type</span> <span class="s">&#39;str&#39;</span><span class="o">&gt;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">valor</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">getint</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">,</span> <span class="s">&#39;numerico&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">type</span><span class="p">(</span><span class="n">valor</span><span class="p">)</span>
<span class="o">&lt;</span><span class="nb">type</span> <span class="s">&#39;int&#39;</span><span class="o">&gt;</span>
</pre></div>
</td></tr></table>

<h2>Editando seções e valores</h2>
<p>Como já foi apresentado, os métodos 
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.add_section" title="add_section">add_section</a></strong> 
e <strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.set" title="set">set</a></strong> são utilizados para 
adicionar novas seções e definir suas opções e valores respectivamente. </p>
<p>Outros métodos úteis são o 
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.remove_section" title="remove_section">remove_section</a></strong>, 
que exclui uma seção e todas as opções associadas e o <strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.remove_option" title="remove_option">remove_option</a></strong> que exclui uma opção em uma determinada seção.</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="o">&gt;&gt;&gt;</span> <span class="c"># Excluindo uma seção</span>
<span class="o">...</span> <span class="n">config</span><span class="o">.</span><span class="n">sections</span><span class="p">()</span>
<span class="p">[</span><span class="s">&#39;section1&#39;</span><span class="p">,</span> <span class="s">&#39;section2&#39;</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">config</span><span class="o">.</span><span class="n">remove_section</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">)</span>
<span class="bp">True</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">config</span><span class="o">.</span><span class="n">sections</span><span class="p">()</span>
<span class="p">[</span><span class="s">&#39;section1&#39;</span><span class="p">]</span>
</pre></div>
</td></tr></table>

<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="o">&gt;&gt;&gt;</span> <span class="c"># Excluindo uma opção</span>
<span class="o">...</span> <span class="n">config</span><span class="o">.</span><span class="n">items</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">)</span>
<span class="p">[(</span><span class="s">&#39;outraopcao&#39;</span><span class="p">,</span> <span class="s">&#39;valor&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;numerico&#39;</span><span class="p">,</span> <span class="s">&#39;123&#39;</span><span class="p">)]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">config</span><span class="o">.</span><span class="n">remove_option</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">,</span> <span class="s">&#39;outraopcao&#39;</span><span class="p">)</span>
<span class="bp">True</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">config</span><span class="o">.</span><span class="n">items</span><span class="p">(</span><span class="s">&#39;section2&#39;</span><span class="p">)</span>
<span class="p">[(</span><span class="s">&#39;numerico&#39;</span><span class="p">,</span> <span class="s">&#39;123&#39;</span><span class="p">)]</span>
</pre></div>
</td></tr></table>

<h2>Armazenando o arquivo</h2>
<p>A instância de ConfigParser é uma representação de um arquivo de configuração. Depois de 
fazer a personalização desejada, é necessário salvá-lo no sistema de arquivos. Isso é feito utilizando o método
<strong><a href="http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.write" title="write">write</a></strong>:</p>
<p>Este código abre um arquivo chamado <em>config.ini</em> para escrita, excluindo todo o conteúdo existente 
e armazena a representação do arquivo de configuração:</p>
<table class="pygments_defaulttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="pygments_default"><pre><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;config.ini&#39;</span><span class="p">,</span> <span class="s">&#39;w&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">cfgfile</span><span class="p">:</span>
    <span class="n">config</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">cfgfile</span><span class="p">)</span>
</pre></div>
</td></tr></table>

<h2>Exemplo</h2>
<p>Aqui temos um exemplo de como criar através de código um arquivo de configuração de uma aplicação 
hipotetica, indicando dados de conexão do banco de dados e repositório: 
<strong><a href="https://gist.github.com/1590437" title="Exemplo de criação de arquivo INI">https://gist.github.com/1590437</a></strong></p>]]></content:encoded>
    </item>
    <item>
      <title>Coding Dojo Kake</title>
      <link>http://rennerocha.com/2011/10/24/coding-dojo-kake</link>
      <pubDate>Mon, 24 Oct 2011 13:37:00 BRST</pubDate>
      <category><![CDATA[dojo]]></category>
      <category><![CDATA[lhc]]></category>
      <guid isPermaLink="true">http://rennerocha.com/2011/10/24/coding-dojo-kake</guid>
      <description>Coding Dojo Kake</description>
      <content:encoded><![CDATA[<p>O formato mais comum de Coding Dojo é conhecido como <a href="http://codingdojo.org/cgi-bin/wiki.pl?RandoriKata">Randori</a>. Neste formato
um problema de programação é resolvido colaborativamente por todos os participantes
sendo que a cada pequeno período de tempo (de 5 a 7 minutos normalmente), uma dupla
de programadores está "no comando" do computador enquanto o restante acompanha tudo
por um projetor.</p>
<p>Porém existem outras maneiras de se realizar um Coding Dojo. Um outro formato, que só
consegui utilizar uma vez no open-space do <a href="http://caipiraagil.com/">Caipira Ágil</a>, é o 
Kake.</p>
<p>Neste formato, temos sempre pelo menos duas duplas trabalhando simultaneamente no mesmo problema
em linguagens diferentes, em problemas diferentes na mesma linguagem ou em problemas diferentes
em linguagens diferentes. A troca das duplas ocorre como no Randori (a cada 5 a 7 minutos), onde o
piloto (quem está com o teclado nas mãos) troca de computador e o co-piloto (que estava ajudando o
piloto), se torna o piloto.</p>
<p>No dia 29/10/2011, às 10h, teremos uma sessão de Coding Dojo utilizando este formato
na sede do LHC (<a href="http://lhc.net.br/">Laboratório Hacker de Campinas</a>). Quem puder, traga
o seu notebook com algum ambiente de desenvolvimento configurado. Aqui você pode encontrar mais informações
sobre <a href="http://lhc.net.br/CodingDojo">o Dojo e como chegar no LHC</a>.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
