<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Desenvolvimento &#193;gil - Blog da Improve It: Tag rails</title>
    <link>http://blog.improveit.com.br/articles/tag/rails</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>Como Testar parte 2 - Mocks</title>
      <description>&lt;blockquote class="excerpt"&gt;
  &lt;p&gt;Tem gente "chutando" Demeter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Minha id&#233;ia era escrever um post dessa s&#233;rie por semana, mas infelizmente uma tendinite tem me atacado e est&#225; meio complicado ficar escrevendo muito. Por isso mesmo esse segundo artigo ser&#225; bem compacto. Todos os c&#243;digos citados nesse post fazem parte de um projeto How Test que est&#225; dispon&#237;vel em: http://github.com/tapajos/how-test&lt;/p&gt;

&lt;p&gt;Nesse post a minha id&#233;ia &#233; mostrar de forma bem simples como funciona um &lt;a href="http://en.wikipedia.org/wiki/Mock_Object"&gt;mock object&lt;/a&gt; no Rspec e no Test::Unit(usando o mocha). &lt;/p&gt;

&lt;p&gt;Para exemplificar eu vou fazer uma cr&#237;tica a uma constru&#231;&#227;o que eu tenho visto muito em diversos projetos e que viola a &lt;a href="http://en.wikipedia.org/wiki/Law_of_Demeter"&gt;Lei de Demeter&lt;/a&gt;(Principle of Least Knowledge). Ou como dizia, o meu amigo, Bernardo, "Tem gente chutando Demeter!". &lt;/p&gt;

&lt;h3&gt;Vamos a um exemplo dessa viola&#231;&#227;o:&lt;/h3&gt;

&lt;p&gt;Supondo que voc&#234; tenha um modelo Account que se relaciona ao modelo User.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Account &amp;lt; ActiveRecord::Base
  belongs_to :user
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Freq&#252;entemente eu vejo constru&#231;&#245;es do tipo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@account.user.name
@account.user.mail
@account.user.rg.number
@account.user.rg.state
@account.user.rg.city
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;O grande problema &#233; que nesse tipo de constru&#231;&#227;o voc&#234; est&#225; "conhecendo" coisas demais e certamente vai pagar por isso num futuro breve, quando voc&#234; precisar fazer um refactoring e tiver que mudar em v&#225;rios lugares. Imagina se o User deixa de ter um "name" e passa a ter um "full_name".&lt;/p&gt;

&lt;p&gt;Para resolver esse tipo de problema basta voc&#234; concentrar esse "conhecimento" no seu modelo Account da seguinte forma:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Account &amp;lt; ActiveRecord::Base
  belongs_to :user
  def user_name
    user.name
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OBS: Vou me concentrar apenas no problema com o nome e n&#227;o vou me preocupar em validar se o relacionamento foi estabelecido.&lt;/p&gt;

&lt;p&gt;Bem, finalizada a cr&#237;tica a uma falha de design OO vamos ao objetivo desse post, mostrar como *EU* testaria esse problema.&lt;/p&gt;

&lt;p&gt;Como eu falei no post anterior, n&#227;o gosto muito de usar fixtures para testes unit&#225;rios e por isso mesmo vou apelar aos &lt;a href="http://en.wikipedia.org/wiki/Mock_Object"&gt;mock objects&lt;/a&gt;. Se voc&#234; n&#227;o est&#225; muito familiarizado com mocks sugiro que pare por aqui e leia um pouco mais sobre isso. Uma refer&#234;ncia r&#225;pida pode ser o &lt;a href="http://en.wikipedia.org/wiki/Mock_Object"&gt;wikipedia&lt;/a&gt; mas realmente sugiro que v&#225; mais adiante.&lt;/p&gt;

&lt;p&gt;Testando usando RSpec(usando o framework de mock padr&#227;o):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;before(:each) do
  @account = Account.new    
  @user_mock = mock_model(User)
  @account.stub!(:user).and_return(@user_mock)
end

describe ".user_name" do

  it "should delegate to user.name" do
    @user_mock.should_receive(:name).and_return("Tapaj&#243;s")
    @account.user_name.should == "Tapaj&#243;s"
  end

end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Testando usando Test::Unit com mocha:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;setup :create_model

def test_user_name
  @user_mock.expects(:name).returns("Tapaj&#243;s")
  assert_equal "Tapaj&#243;s", @account.user_name
end

private

  def create_model
    @account = Account.new
    @user_mock = mock("User")
    @account.stubs(:user).returns(@user_mock)
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Explicando...&lt;/h3&gt;

&lt;p&gt;Em ambos os casos eu preciso que a minha account simule o relacionamento com User e para isso eu vou retornar um mock object. Isso &#233; feito pelas linhas:&lt;/p&gt;

&lt;p&gt;RSpec:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@account.stub!(:user).and_return(@user_mock)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Test::Unit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@account.stubs(:user).returns(@user_mock)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ap&#243;s o setup ou o before, temos um modelo @account onde o @account.user retorna um mock.&lt;/p&gt;

&lt;p&gt;Feito isso eu preciso configurar o meu mock, isto &#233;, informar que ele receber&#225; uma mensagem name (chamada do m&#233;todo .name) e essa retornar&#225; o meu nome(sim, sou egoc&#234;ntrico). Isso &#233; feito pelos m&#233;todos "should_receive" e "expects" conforme as linhas abaixo:&lt;/p&gt;

&lt;p&gt;RSpec:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@user_mock.should_receive(:name).and_return("Tapaj&#243;s")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Test::Unit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@user_mock.expects(:name).returns("Tapaj&#243;s")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Depois que nossos mocks foram devidamente configurados podemos, finalmente, fazer nossa verifica&#231;&#227;o do retorno, isto &#233;, simplesmente chamar nossos m&#233;todos conferir o retorno. Pronto teste feito com sucesso, sem precisar recorrer a banco de dados nem configurar fixtures.&lt;/p&gt;

&lt;p&gt;Nesse momento deve ter surgido uma d&#250;vida: "Porque uma hora voc&#234; usa stub! e outra um should_receive?"&lt;/p&gt;

&lt;p&gt;A resposta &#233; bem simples, o stub! n&#227;o faz um verify no final enquanto a outra chamada sim. Na pratica isso significa:&lt;/p&gt;

&lt;h3&gt;Stub! ou stubs&lt;/h3&gt;

&lt;p&gt;Quando eu uso stub!(ou um Stubs) eu estou configurando o meu modelo account para responder pelo m&#233;todo user retornando o @mock_user por&#233;m n&#227;o me interessa quebrar esse teste caso voc&#234; n&#227;o chame esse m&#233;todo.&lt;/p&gt;

&lt;h3&gt;Should_receive ou expects&lt;/h3&gt;

&lt;p&gt;Quando eu uso should_receive(ou um expects) eu estou configurando o meu mock user para responder pelo m&#233;todo name por&#233;m caso esse m&#233;todo n&#227;o seja chamado eu devo quebrar meu teste, pois isso seria um comportamento indesej&#225;vel.&lt;/p&gt;

&lt;h2&gt;Porque usar mocks?&lt;/h2&gt;

&lt;p&gt;Ao contr&#225;rio do que muita gente pensa o uso de mocks n&#227;o &#233; um bicho de 7 cabe&#231;as, &#233; bem simples. Na verdade testar &#233; algo simples, desde que voc&#234; tenha dom&#237;nio do ferramental e os mocks s&#227;o realmente &#250;teis em diversos casos.&lt;/p&gt;

&lt;p&gt;Imagina que o seu sistema precise fazer consultas a uma api publica do Yahoo e para isso voc&#234; tenha criado uma classe de consultas. Voc&#234; n&#227;o vai querer(nem o Yahoo vai gostar) ir l&#225; no servidor toda vez que voc&#234; rodar os seus testes. Isso tornaria os seus testes lentos e imposs&#237;vel roda-los offline. Nesse caso voc&#234; resolve seu problema "mockando" essa classe.&lt;/p&gt;</description>
      <pubDate>Sun, 16 Nov 2008 18:22:13 -0200</pubDate>
      <guid isPermaLink="false">urn:uuid:bf5b906d-9cec-4301-8cd1-f6480e1d406b</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/11/16/como-testar-parte-2-mocks</link>
      <category>rails</category>
      <category>rspec</category>
      <category>rspec_on_rails</category>
      <category>ruby</category>
      <category>test</category>
      <category>Testes</category>
      <category>unit</category>
    </item>
    <item>
      <title>Como Testar parte 1 - Models</title>
      <description>&lt;p&gt;Quando comecei a estudar &lt;a href="http://www.improveit.com.br/xp"&gt;Extreme Programming&lt;/a&gt; descobri que n&#227;o &#233; poss&#237;vel fazer nenhum software de qualidade sem uma excelente base de testes. Desde ent&#227;o tenho me dedicado muito ao estudo das mais diversas ferramentas e t&#233;cnicas para elaborar bons de testes.&lt;/p&gt;

&lt;p&gt;O assunto testes &#233; bastante pol&#234;mico e n&#227;o pretendo (nesse post) tentar convencer ningu&#233;m da import&#226;ncia deles. Se voc&#234; n&#227;o faz testes e/ou discorda de qualquer uma das minhas afirma&#231;&#245;es deixo algumas perguntas para voc&#234; refletir.&lt;/p&gt;

&lt;p&gt;1 - Quantos bugs fixes voc&#234; fez esse ano?&lt;/p&gt;

&lt;p&gt;2 - Quantos tickets abertos existem no seu bug tracker?&lt;/p&gt;

&lt;p&gt;3 - Quantas vezes voc&#234; fez um deploy de uma nova vers&#227;o em uma sexta feira de tarde e saiu mais cedo do trabalho?&lt;/p&gt;

&lt;p&gt;4 - Quantas vezes voc&#234; "virou a noite" esse ano?&lt;/p&gt;

&lt;p&gt;Acabei me tornando um evangelizador de testes por&#233;m nunca fiz nada muito pr&#225;tico para passar o conhecimento que eu adquiri para a comunidade. S&#243; que agora vou me redimir dessa falha iniciando uma s&#233;rie de posts onde vou expor um problema e como EU testaria usando Test::Unit e Rspec. N&#227;o vou falar de Shoulda pois n&#227;o gosto dele. :-)&lt;/p&gt;

&lt;p&gt;A id&#233;ia de escrever essa s&#233;rie de posts sobre testes surgiu logo ap&#243;s a grava&#231;&#227;o do terceiro epis&#243;dio do &lt;a href="http://railsbox.org/2008/9/9/railsbox-podcast-3"&gt;RailsBox&lt;/a&gt; e gostaria de agradecer ao Ozeias e ao Davis Cabral por terem me motivado.&lt;/p&gt;

&lt;p&gt;"Back to the cold cow..."&lt;/p&gt;

&lt;p&gt;O ActiveRecord simplifica muito nossos modelos por&#233;m tenho observado que em v&#225;rios projetos os desenvolvedores deixam de testar corretamente os seus modelos usando a  alega&#231;&#227;o que n&#227;o v&#227;o testar alguma coisa que o Rails j&#225; testou. Esse &#233; um argumento valido em alguns casos pois voc&#234; est&#225; apenas delegando responsabilidades mas voc&#234; sempre deve testar se a responsabilidade foi realmente delegada.&lt;/p&gt;

&lt;p&gt;Um exemplo cl&#225;ssico s&#227;o as valida&#231;&#245;es. Teoricamente voc&#234; n&#227;o precisaria testar como elas s&#227;o implementadas mas deve testar se elas realmente existem pois se algu&#233;m remove-las seus testes v&#227;o continuar passando mas sua aplica&#231;&#227;o estar&#225; quebrada e/ou permitindo inconsist&#234;ncias de banco de dados.&lt;/p&gt;

&lt;p&gt;Nesse post vou mostrar como testar alguns comportamento do ActiveRecord usando como base o modelo User. Todos os c&#243;digos citados nesse post fazem parte de um projeto How Test que est&#225; dispon&#237;vel em: http://github.com/tapajos/how-test&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class User &amp;lt; ActiveRecord::Base
  validates_presence_of :name
  validates_format_of :mail, 
                      :with =&amp;gt; /([-.\w^@]+@(?:[-\w]+.)+[A-Za-z]{2,4})+/i,
                      :on =&amp;gt; :create,
                      :allow_nil =&amp;gt; true
  has_many :accounts
  named_scope :actives, :conditions =&amp;gt; ["active = ?", true]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Uma boa estrat&#233;gia para orientar o desenvolvimento dos teste &#233; elaborar algumas perguntas que dar&#227;o origem aos seus cen&#225;rios de testes.&lt;/p&gt;

&lt;h3&gt;Valida&#231;&#227;o do nome&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Posso cadastrar um usu&#225;rio sem nome? N&#227;o&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Testando usando Test:Unit:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;def test_if_check_presence_of_name
  assert !@user.valid?, "Should be invalid"
  assert_equal "can't be blank", @user.errors[:name]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Na primeira linha desse teste o assert recebe um segundo par&#226;metro que por ser opcional n&#227;o &#233; muito comentado mas merece uma aten&#231;&#227;o especial. Esse argumento nada mais &#233; do que a mensagem que ser&#225; exibida quando o teste quebrar. Quando voc&#234; omite esse par&#226;metro o teste quebra exibindo a mensagem 'false is not true' que n&#227;o ajuda muito a entender o que est&#225; acontecendo.&lt;/p&gt;

&lt;h4&gt;Testando usando RSpec:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;it "should reject if name is not given" do
  @user.should have(1).error_on(:name)
  @user.errors[:name].should == "can't be blank"
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Valida&#231;&#227;o do e-mail.&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Posso criar um registro com um e-mail inv&#225;lido? N&#227;o&lt;/li&gt;
&lt;li&gt;Posso atualizar um regitro com um e-mail inv&#225;lido? Sim&lt;/li&gt;
&lt;li&gt;Posso criar um registro com um e-mail em branco? Sim&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Testando usando Test:Unit:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;VALIDS_MAIL = %w(foo@bar.com foo@bar.com.br foo@globo.com foo@i_hate_the_microsoft.com foo@i_love_my_mac.com)
INVALIDS_MAIL = %w(foobar.com foo@bar i_hate_the_microsoft.com i_love_my_mac.com)

def test_if_reject_invalid_format_os_mail_on_create
  INVALIDS_MAIL.each do |mail|
    @user.mail = mail
    assert !@user.valid?, "Should be invalid when mail is #{mail}"
    assert_equal "is invalid", @user.errors[:mail]
  end
end

def test_if_not_reject_when_mail_is_nil
  @user.name = "Tapaj&#243;s"
  assert @user.valid?, "Should be valid"
end

def test_if_not_check_format_of_mail_on_update
  @user.name = "Tapaj&#243;s"
  assert @user.save, "Should save"
  @user.mail = "an invalid mail"
  assert @user.valid?, "Should be valid"
end

def test_if_accept_a_valid_mail
  VALIDS_MAIL.each do |mail|
    @user.name = "Tapaj&#243;s"
    @user.mail = mail
    assert @user.valid?, "Should be valid when mail is #{mail}"
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Testando usando RSpec:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;INVALIDS_MAIL.each do |mail|
  it "should reject because #{mail} is an invalid mail" do
    @user.mail = mail
    @user.should have(1).error_on(:mail)
    @user.errors[:mail].should == "is invalid"
  end
end

VALIDS_MAIL.each do |mail|
  it "should be valid when mail is #{mail}" do
    @user.mail = mail
    @user.should_not have(1).error_on(:mail)
  end
end

it "should not reject if mail is not given" do
  @user.name = "Tapaj&#243;s"
  @user.should be_valid
end

it "should not check mail format on update" do
    @user.name = "Tapaj&#243;s"
    @user.save.should be_true
    @user.mail = "an invalid mail"
    @user.should be_valid
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Testando o relacionamento com Account.&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Um usu&#225;rio pode ter mais de uma conta? Sim&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Testando usando Test::Unit:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;def test_has_many_accounts
  association = User.reflect_on_association(:accounts)
  assert association, "Association with account is not found"
  assert_equal :has_many, association.macro
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Testando usando RSpec:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;it "should has many accounts" do
  association = User.reflect_on_association(:accounts)
  association.should_not be_nil
  association.macro.should == :has_many
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Testando o User.actives&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Posso listar usu&#225;rios inativos? N&#227;o&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Testando usando Test::Unit:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;def test_if_actives_use_the_correct_conditions
  assert_equal({:conditions=&amp;gt;["active = ?", true]}, User.actives.proxy_options)
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Testando usando RSpec:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;it "should find for all users that status of active is true" do
  User.actives.proxy_options.should == {:conditions=&amp;gt;["active = ?", true]}
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Para esse post ficar mais simples e curto n&#227;o me preocupei em validar se o tamanho m&#225;ximo dos campos est&#225; coerente com o tamanho m&#225;ximo permitido pelo tipo no banco de dados. Essa &#233; uma valida&#231;&#227;o EXTREMAMENTE importante que n&#227;o deve ser esquecida!&lt;/p&gt;

&lt;p&gt;No pr&#243;ximo post dessa s&#233;rie falarei um pouco sobre a &lt;a href="http://en.wikipedia.org/wiki/Law_of_Demeter"&gt;Lei de Demeter&lt;/a&gt;, como respeita-la e testar alguns m&#233;todos usando &lt;a href="http://en.wikipedia.org/wiki/Mock_Object"&gt;Mock Objects&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O que voc&#234; achou desse artigo? O que voc&#234; gostaria de saber sobre testes de ActiveRecord que eu n&#227;o falei aqui?&lt;/p&gt;

&lt;p&gt;Aguardo o feedback de voc&#234;s.&lt;/p&gt;</description>
      <pubDate>Sun, 26 Oct 2008 02:51:35 -0200</pubDate>
      <guid isPermaLink="false">urn:uuid:aa3262eb-fd9b-4304-9bb1-f6ef0d945ee2</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/10/26/como-testar-parte-1-models</link>
      <category>rspec</category>
      <category>test</category>
      <category>unit</category>
      <category>Testes</category>
      <category>ruby</category>
      <category>rails</category>
      <category>rspec_on_rails</category>
    </item>
    <item>
      <title>Mais uma gem no Brazilian Rails</title>
      <description>&lt;p&gt;O Brazilian Rails acabou de ganhar uma gem para lidar com CPF e CNPJ desenvolvida pelo C&#225;ssio Marques. Ele fez um &lt;a href="http://cassiomarques.wordpress.com/2008/09/24/brazilian-rails-agora-com-suporte-a-cpf-e-cnpj/"&gt;post&lt;/a&gt; no seu blog explicando como utilizar.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://tinyurl.com/cpfcnpj
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Al&#233;m dessa nova gem a vers&#227;o 2.0.8 do Brazilian Rails recebeu algumas pequenas corre&#231;&#245;es feitas pelo &lt;a href="http://www.akitaonrails.com/"&gt;Akita&lt;/a&gt; e pelo Sergio Brant.&lt;/p&gt;

&lt;p&gt;Gostaria de agradecer aos tr&#234;s pelas colabora&#231;&#245;es.&lt;/p&gt;</description>
      <pubDate>Tue, 23 Sep 2008 23:20:36 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:ca5f52c6-54b6-450d-81db-08cdb276b1e9</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/09/23/mais-uma-gem-no-brazilian-rails</link>
      <category>gem</category>
      <category>ruby</category>
      <category>rails</category>
      <category>brazilianrails</category>
      <category>cpf</category>
      <category>cnpj</category>
    </item>
    <item>
      <title>Integration Plugin no Github</title>
      <description>&lt;p&gt;Acabamos de migrar o &lt;a href="http://integration.rubyforge.org/"&gt;Integration plugin&lt;/a&gt; para o Github. 
As instru&#231;&#245;es de instala&#231;&#227;o podem ser conferidas na p&#225;gina do projeto em:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://integration.rubyforge.org/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A p&#225;gina do projeto no Github &#233;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://github.com/tapajos/integration
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Fri, 05 Sep 2008 14:49:52 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:a5491516-c9d7-4ad2-a4c1-4fe6660655e0</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/09/05/integration-plugin-no-github</link>
      <category>integration</category>
      <category>plugin</category>
      <category>rails</category>
      <category>github</category>
      <category>git</category>
    </item>
    <item>
      <title>Saiu o Brazilian Rails 2.0 </title>
      <description>&lt;p&gt;Finalmente terminamos a migra&#231;&#227;o do plugin Brazilian Rails para ser um conjunto de gems! Agora vamos come&#231;ar duas novas empreitadas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Migrar as gems que s&#227;o espec&#237;ficas para o Rails para usarem o i18n.&lt;/li&gt;
&lt;li&gt;Conversar com todos os desenvolvedores que possuem plugins espec&#237;ficos para brasileiros para transformar em gems e adicionar ao Brazilian Rails.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Voc&#234;s podem ver mais detalhes em:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://www.improveit.com.br/software_livre/brazilian_rails
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Sun, 31 Aug 2008 23:57:34 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:07333907-af6d-43d0-b691-b8e23316cd2c</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/08/31/saiu-o-brazilian-rails-2-0</link>
      <category>brazilian</category>
      <category>rails</category>
      <category>plugin</category>
      <category>gem</category>
    </item>
    <item>
      <title>Entrevista com Marcelo Alvim, do Projeto Lucidus</title>
      <description>&lt;p&gt;H&#225; algumas semanas eu entrevistei os desenvolvedores do &lt;a href="http://blog.improveit.com.br/articles/2007/05/15/xp-rio-conheca-o-projeto-xp-do-grupo-santa-isabel"&gt;Projeto Lucidus&lt;/a&gt;. Abaixo a entrevista com o &lt;a href="http://www.improveit.com.br/empresa/marcelo"&gt;Marcelo Alvim&lt;/a&gt;, que faz parte da equipe da &lt;a href="http://www.improveit.com.br"&gt;Improve It&lt;/a&gt; no projeto:&lt;/p&gt;

&lt;p&gt;&lt;object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="545" height="451" id="viddler_ad08b93f"&gt;&lt;param name="movie" value="http://www.viddler.com/player/ad08b93f/" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;embed src="http://www.viddler.com/player/ad08b93f/" width="545" height="451" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" name="viddler_ad08b93f" &gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;

&lt;p&gt;Quem tiver iPhone pode ver a &lt;a href="http://www.youtube.com/watch?v=ir77FTYqUng"&gt;entrevista no YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.viddler.com/explore/vinicius/videos/7/"&gt;Link direto para o v&#237;deo.&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://www.viddler.com/explore/vinicius/videos/7.flv"&gt;Download .flv&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://www.viddler.com/explore/vinicius/videos/7.m4v"&gt;Download .m4v&lt;/a&gt;  &lt;/p&gt;</description>
      <pubDate>Tue, 19 Aug 2008 15:16:00 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:a896809f-107f-4cb7-9bad-b72092dc421c</guid>
      <author>Vinicius Manh&#227;es Teles</author>
      <link>http://blog.improveit.com.br/articles/2008/08/19/entrevista-com-marcelo-alvim-do-projeto-lucidus</link>
      <category>v&#237;deo</category>
      <category>xp</category>
      <category>agile</category>
      <category>extreme programming</category>
      <category>desenvolvimento &#225;gil</category>
      <category>lucidus</category>
      <category>programa&#231;&#227;o em par</category>
      <category>rails</category>
    </item>
    <item>
      <title>Hotel para a Rails Summit</title>
      <description>&lt;p&gt;&lt;a href="http://www.locaweb.com.br/railssummit"&gt;
&lt;img src="http://www.akitaonrails.com/assets/2008/8/1/468x60.gif" 
alt="Rails Summit Latin America" title="Rails Summit Latin America" 
border="0" width="468" height="60"/&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No meu &lt;a href="http://blog.improveit.com.br/articles/2008/07/29/rails-summit-latin-america-2008"&gt;&#250;ltimo post&lt;/a&gt; eu comentei sobre o hotel em que ficaremos hospedados para a Rails Summit Latin America 2008 e algumas pessoas comentaram que o hotel est&#225; lotado.&lt;/p&gt;

&lt;p&gt;Eu liguei l&#225; no hotel e descobri que existem quartos dispon&#237;veis mas que eles liberam apenas alguns pela central 0800 e o resto s&#243; ligando direto para o hotel. Ou seja, quem quiser reservar &#233; bom ligar para: 11-4506-9500&lt;/p&gt;</description>
      <pubDate>Wed, 30 Jul 2008 04:45:54 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:0d23fd89-6988-4d03-b1c2-1202caefc25b</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/07/30/hotel-para-a-rails-summit</link>
      <category>rails</category>
    </item>
    <item>
      <title>Rails Summit Latin America 2008</title>
      <description>&lt;p&gt;&lt;a href="http://www.locaweb.com.br/railssummit"&gt;
&lt;img src="http://www.akitaonrails.com/assets/2008/8/1/468x60.gif" 
alt="Rails Summit Latin America" title="Rails Summit Latin America" 
border="0" width="468" height="60"/&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Em outubro teremos a maior confer&#234;ncia de Rails no Brasil, a &lt;a href="http://www.akitaonrails.com/2008/7/13/rails-summit-latin-america-2008"&gt;Rails Summit Latin America 2008&lt;/a&gt; que est&#225; sendo organizada pelo nosso amigo &lt;a href="http://www.akitaonrails.com"&gt;F&#225;bio Akita&lt;/a&gt;. Ser&#225; uma confer&#234;ncia de alto n&#237;vel, com os grandes nomes internacionais e nacionais.&lt;/p&gt;

&lt;p&gt;Eu irei ao evento juntamente com parte da equipe da &lt;a href="http://www.improveit.com.br"&gt;Improve It&lt;/a&gt; e da &lt;a href="http://www.surgeworks.com"&gt;Surgeworks&lt;/a&gt;. Esse evento tamb&#233;m ser&#225; uma &#243;tima oportunidade de cair na farra com alguns amigos que n&#227;o vemos sempre. 
Para facilitar a organiza&#231;&#227;o da bagun&#231;a que iremos fazer resolvemos que seria legal informar a todos o &lt;a href="http://www.bwmetrotietehotel.com.br"&gt;hotel&lt;/a&gt; que n&#243;s ficaremos para atrair mais adeptos a nossa farra!&lt;/p&gt;

&lt;p&gt;Eu n&#227;o conhe&#231;o o &lt;a href="http://www.bwmetrotietehotel.com.br"&gt;hotel&lt;/a&gt; e n&#227;o sei dizer se ele &#233; bom ou ruim, apenas fui na indica&#231;&#227;o de uns amigos l&#225; de SP e eu n&#227;o conto que s&#227;o todos da &lt;a href="http://www.surgeworks.com"&gt;Surgeworks&lt;/a&gt; nem que me cortem o pesco&#231;o. Mas nem estou me preocupando com isso, s&#243; quero o hotel para dormir mesmo! :-)&lt;/p&gt;

&lt;p&gt;Bem, que Deus proteja o &lt;a href="http://www.bwmetrotietehotel.com.br"&gt;hotel&lt;/a&gt;!&lt;/p&gt;</description>
      <pubDate>Tue, 29 Jul 2008 19:31:13 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:4c4599fd-c171-45bd-ac24-db0152c0803f</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/07/29/rails-summit-latin-america-2008</link>
      <category>rails</category>
    </item>
    <item>
      <title>Em Julho: Ultra Maratona How To! Com cursos de Rails e XP!</title>
      <description>&lt;p&gt;&lt;img src="http://mergulhao.info/assets/2008/6/14/maratona.jpg" style="float: left; padding: 5px" alt="Logo Maratona"/&gt;&lt;/p&gt;

&lt;p&gt;Nos dias 19 e 20 de julho teremos no Rio de Janeiro a I Ultra Maratona How To de Software Livre! &#201; um evento com 20 tutoriais pr&#225;ticos de 4 horas cada. Ter&#227;o desde cursos de utiliza&#231;&#227;o de BrOffice e Inkscape, passando por seguran&#231;a de servidores, hardening e desenvolvimento. Para ver a &lt;a href="http://www.ultramaratonahowto.com.br/tutoriais.htm"&gt;grade completa acesse&lt;/a&gt;. Os pre&#231;os s&#227;o bem convidativos.&lt;/p&gt;

&lt;p&gt;Eu serei tutor de dois. O primeiro, com nome de "XP Game e o Jogo da comunica&#231;&#227;o", ser&#225; em conjunto com o &lt;a href="http://www.improveit.com.br/empresa/tapajos"&gt;Tapajos&lt;/a&gt; e a galera do &lt;a href="http://blog.improveit.com.br/articles/2007/05/15/xp-rio-conheca-o-projeto-xp-do-grupo-santa-isabel"&gt;Lucidus&lt;/a&gt;. No segundo estarei sozinho e ser&#225; uma "Introdu&#231;&#227;o ao Ruby on Rails".&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.ultramaratonahowto.com.br"&gt;Acesse j&#225; e fa&#231;a a sua inscri&#231;&#227;o&lt;/a&gt;, as vagas s&#227;o limitadas.&lt;/p&gt;</description>
      <pubDate>Sun, 06 Jul 2008 16:44:00 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:0a7104ef-947c-4b17-8189-98a0de6e3e56</guid>
      <author>Sylvestre Mergulh&#227;o</author>
      <link>http://blog.improveit.com.br/articles/2008/07/06/em-julho-ultra-maratona-how-to</link>
      <category>treinamento</category>
      <category>confer&#234;ncia</category>
      <category>xp</category>
      <category>rails</category>
      <category>workshop</category>
    </item>
    <item>
      <title>Integration Plugin com GIT</title>
      <description>&lt;p&gt;Agora o &lt;a href="http://integration.rubyforge.org/"&gt;Integration Plugin&lt;/a&gt; suporta GIT!&lt;/p&gt;

&lt;p&gt;&lt;img src="http://blog.improveit.com.br/files/2008-06-25_intplugin.gif" alt="intplugin"/&gt;&lt;/p&gt;

&lt;p&gt;Desde o lan&#231;amento do &lt;a href="http://integration.rubyforge.org/"&gt;Integration Plugin&lt;/a&gt; eu tinha a sensa&#231;&#227;o que faltava o suporte ao GIT por&#233;m como o &lt;a href="http://integration.rubyforge.org/"&gt;plugin&lt;/a&gt; foi extra&#237;do dos nossos c&#243;digos e n&#227;o us&#225;vamos esse SCM ele foi lan&#231;ado assim mesmo.&lt;/p&gt;

&lt;p&gt;Logo depois o &lt;a href="http://tudoquequerosaber.com/"&gt;Eduardo Fiorezi&lt;/a&gt; me enviou um patch adicionando esse suporte e posteriormente o suporte ao git-svn s&#243; que eu n&#227;o aceitei de imediato pois faltava documentar e eu estava completamente sem tempo para isso. S&#243; que hoje recebi um patch do &lt;a href="http://mergulhao.info/"&gt;Sylvestre Mergulh&#227;o&lt;/a&gt; atualizando a documenta&#231;&#227;o.&lt;/p&gt;

&lt;p&gt;Obrigado aos dois!&lt;/p&gt;</description>
      <pubDate>Wed, 25 Jun 2008 20:31:35 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:846af183-4877-439b-92ad-e902b1c3dc77</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/06/25/integration-plugin-com-git</link>
      <category>integration</category>
      <category>plugin</category>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Agora &#233; a hora!</title>
      <description>&lt;p&gt;Como eu falei no meu outro &lt;a href="http://blog.improveit.com.br/articles/2008/06/21/o-futuro-do-brazilian-rails"&gt;post&lt;/a&gt;, n&#243;s estamos refatorando o &lt;a href="http://www.improveit.com.br/software_livre/brazilian_rails"&gt;Brazilian Rails&lt;/a&gt; e essa &#233; a hora para quem quiser dar grandes sugest&#245;es e/ou colabora&#231;&#245;es. Quem quiser comentar algo ou fa&#231;a agora ou cale-se para sempre! :-)&lt;/p&gt;

&lt;p&gt;Tudo que estamos mexendo est&#225; em um branch chamado gems l&#225; no Github. Para baixar o c&#243;digo basta seguir esses passos:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone git://github.com/tapajos/brazilian-rails.git
cd brazilian-rails
git checkout --track -b gems origin/gems
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Mon, 23 Jun 2008 00:24:45 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:5689d44a-3daa-479d-b148-20d894f2d9fb</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/06/23/agora-%C3%A9-a-hora</link>
      <category>brazilian</category>
      <category>rails</category>
      <category>brazilianrails</category>
    </item>
    <item>
      <title>O futuro do Brazilian Rails</title>
      <description>&lt;p&gt;J&#225; faz um bom tempo que o &lt;a href="http://tinogomes.wordpress.com/"&gt;Tino&lt;/a&gt; conversou comigo sobre rescrever o &lt;a href="http://www.improveit.com.br/software_livre/brazilian_rails"&gt;Brazilian Rails&lt;/a&gt; s&#243; que n&#243;s fomos adiando e acabou n&#227;o saindo nada. Freq&#252;entemente n&#243;s recebemos v&#225;rias sugest&#245;es e queria dizer que todas est&#227;o sendo analisadas e algumas j&#225; est&#227;o na nossa agenda(no meio digital dois corpos ocupam o mesmo espa&#231;o!).&lt;/p&gt;

&lt;p&gt;Essa semana o C&#225;ssio e o Hallison deram a sugest&#227;o de modularizar o plugin para poder instalar apenas o que &#233; realmente &#250;til para um determinado projeto. Foi uma sugest&#227;o que n&#227;o &#233; in&#233;dita mas que eu juntei com uma outra que eu recebi faz um bom tempo que &#233; transformar o plugin em uma gem para n&#227;o precisar instalar em cada projeto.&lt;/p&gt;

&lt;p&gt;A id&#233;ia &#233; tornar um &lt;a href="http://www.improveit.com.br/software_livre/brazilian_rails"&gt;Brazilian Rails&lt;/a&gt; em um conjunto de gems de forma bem semelhante ao Rails mas que poder&#225; ser usado como plugin da mesma forma como &#233; usado hoje. Bem, esse &#233; o futuro!&lt;/p&gt;

&lt;p&gt;Pois bem, fiz um branch chamado gems l&#225; no nosso &lt;a href="http://github.com/tapajos/brazilian-rails"&gt;reposit&#243;rio&lt;/a&gt; e j&#225; estou trabalhando na futura vers&#227;o do &lt;a href="http://www.improveit.com.br/software_livre/brazilian_rails"&gt;Brazilian Rails&lt;/a&gt;. Se algu&#233;m quiser olhar e dar sugest&#245;es..&lt;/p&gt;</description>
      <pubDate>Sat, 21 Jun 2008 21:10:26 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:7341e563-0784-4310-a3d1-37b4a012e2ea</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/06/21/o-futuro-do-brazilian-rails</link>
      <category>rails</category>
      <category>brazilian</category>
      <category>brazilianrails</category>
    </item>
    <item>
      <title>O primeiro livro sobre Rails 2.1 &#233; brasileiro!</title>
      <description>&lt;p&gt;Eu e o &lt;a href="http://www.nomedojogo.com"&gt;Carlos Brando&lt;/a&gt; acabamos de liberar o primeiro &lt;a href="http://www.nomedojogo.com/2008/06/06/o-primeiro-livro-sobre-rails-21-e-brasileiro"&gt;livro&lt;/a&gt; sobre Rails 2.1. &lt;/p&gt;

&lt;p&gt;Quem quiser ver mais detalhes &#233; s&#243; olhar o &lt;a href="http://www.nomedojogo.com/2008/06/06/o-primeiro-livro-sobre-rails-21-e-brasileiro"&gt;post&lt;/a&gt; que o &lt;a href="http://www.nomedojogo.com"&gt;Carlos&lt;/a&gt; fez.&lt;/p&gt;</description>
      <pubDate>Fri, 06 Jun 2008 15:23:37 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:9ab33bc6-e3c4-4651-905f-51f6ef9a3cf8</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/06/06/o-primeiro-livro-sobre-rails-2-1-%C3%A9-brasileiro</link>
      <category>rubyonrails</category>
      <category>rails</category>
      <category>livro</category>
      <category>2.1</category>
    </item>
    <item>
      <title>Bug no Selenium on Rails ser&#225; corrigido!</title>
      <description>&lt;p&gt;Em janeiro desse ano eu publiquei um &lt;a href="http://blog.improveit.com.br/articles/2007/12/15/plugin-selenium-on-rails-no-rails-2-0"&gt;post&lt;/a&gt; relatando um bug no plugin &lt;a href="http://selenium-on-rails.openqa.org/"&gt;Selenium on Rails&lt;/a&gt; e at&#233; hoje o ticket estava aberto. Durante esses 5 meses eu recebi v&#225;rios e-mails de pessoas que chegaram ao meu post mas n&#227;o entendiam o idioma e para todas elas eu respondia como corrigir e reclamava que o projeto parecia abandonado. &lt;/p&gt;

&lt;p&gt;Recentemente eu entrei em contato com o &lt;a href="http://www.dtsato.com"&gt;Danilo Sato&lt;/a&gt; para ver se ele descobria, l&#225; na &lt;a href="http://www.thoughtworks.com/"&gt;ThoughtWorks&lt;/a&gt;, quem era o dono do projeto s&#243; que n&#227;o tivemos muito sucesso. Eu estava quase pensando em fazer um fork mas hoje tive uma resposta do meu ticket e acredito que o projeto voltar&#225; a ser mantido. O Eric vai aplicar o patch que eu mandei e finalmente as pessoas v&#227;o poder usar o plugin com o Rails 2.0 sem ter que marretar o c&#243;digo. &lt;/p&gt;

&lt;p&gt;Antes tarde do que nunca!&lt;/p&gt;</description>
      <pubDate>Wed, 21 May 2008 00:00:10 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:5d38edd7-3d78-4677-8680-4a3edd5871b2</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/05/21/bug-no-selenium-on-rails-ser%C3%A1-corrigido</link>
      <category>selenium</category>
      <category>rails</category>
      <category>plugin</category>
      <category>selenium_on_rails</category>
      <category>Selenium on Rails</category>
    </item>
    <item>
      <title>Brazilian Rails no github</title>
      <description>&lt;p&gt;Acabei de terminar a migra&#231;&#227;o do plugin &lt;a href="http://brazilian-rails.rubyforge.org/"&gt;Brazilian Rails&lt;/a&gt; para o &lt;a href="http://github.com/"&gt;github&lt;/a&gt;. Achei que ia ser bem mais complicado do que foi ! :-)&lt;/p&gt;

&lt;p&gt;N&#243;s decidimos manter o &lt;a href="svn://rubyforge.org/var/svn/brazilian-rails"&gt;SVN&lt;/a&gt; como um espelho (por um tempo) para facilitar a instala&#231;&#227;o nas vers&#245;es anteriores a Rails Edge. Agora existem duas formas de instala&#231;&#227;o que est&#227;o detalhadas na &lt;a href="http://brazilian-rails.rubyforge.org/"&gt;p&#225;gina&lt;/a&gt; do plugin.&lt;/p&gt;

&lt;p&gt;Para quem quiser acompanhar o projeto a url no &lt;a href="http://github.com/"&gt;github&lt;/a&gt; &#233;:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/tapajos/brazilian-rails"&gt;http://github.com/tapajos/brazilian-rails&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 22 Apr 2008 15:33:13 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:f685cf7c-f485-4dea-8896-4426d2424b75</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/04/22/brazilian-rails-no-github</link>
      <category>git</category>
      <category>github</category>
      <category>brazilianrails</category>
      <category>ruby</category>
      <category>rails</category>
      <category>plugin</category>
    </item>
    <item>
      <title>Novidades no Brazilian Rails</title>
      <description>&lt;p&gt;O &lt;a href="http://tinogomes.wordpress.com"&gt;Tino&lt;/a&gt; acabou de publicar no &lt;a href="http://tinogomes.wordpress.com/2008/04/18/novidades-no-brazilian-rails/"&gt;blog&lt;/a&gt; dele as &#250;ltimas mudan&#231;as do &lt;a href="http://brazilian-rails.rubyforge.org"&gt;Brazilian Rails&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Thu, 17 Apr 2008 18:54:46 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:58d2db28-1acd-4e75-977d-f89c0a41e8d1</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/04/17/novidades-no-brazilian-rails</link>
      <category>brazilianrails</category>
      <category>plugin</category>
      <category>rails</category>
    </item>
    <item>
      <title>Nova P&#225;gina para o Brazilian Rails</title>
      <description>&lt;p&gt;Hoje o &lt;a href="http://brazilian-rails.rubyforge.org/"&gt;Brazilian Rails&lt;/a&gt; ganhou um &lt;a href="http://brazilian-rails.rubyforge.org/"&gt;site&lt;/a&gt; um pouco mais bonitinho com um design igual ao do nosso outro &lt;a href="http://integration.rubyforge.org/"&gt;plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Na verdade esse &#233; um template, de autoria do &lt;a href="http://www.improveit.com.br"&gt;Leandro&lt;/a&gt;, que ser&#225; usado em todos os nossos plugins. S&#243; n&#227;o est&#225; mais bonito pois resolvi meter a m&#227;o e me antecipar ao &lt;a href="http://www.improveit.com.br"&gt;Leandro&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Tue, 25 Mar 2008 19:47:57 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:2472e736-c276-49c8-a948-7150a5e744e6</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/03/25/nova-p%C3%A1gina-para-o-brazilian-rails</link>
      <category>brazilianrails</category>
      <category>plugin</category>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Brazilian Rails: Patch aceito.</title>
      <description>&lt;p&gt;Como sempre estou atrasado e s&#243; hoje vi alguns patch no &lt;a href="http://brazilian-rails.rubyforge.org/api"&gt;Brazilian Rails&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Patch #17896 - usar_como_dinheiro n&#227;o funciona com audit.&lt;/h3&gt;

&lt;p&gt;O &lt;a href="http://mergulhao.info/"&gt;Sylvestre Mergulh&#227;o&lt;/a&gt; identificou uma incompatibilidade do &lt;a href="http://brazilian-rails.rubyforge.org/api"&gt;plugin&lt;/a&gt; com o &lt;a href="http://agilewebdevelopment.com/plugins/acts_as_audited"&gt;audit&lt;/a&gt; que n&#227;o fazia log das colunas mapeadas com o usar_como_dinheiro.
O patch que ele enviou j&#225; foi aceito.&lt;/p&gt;

&lt;h3&gt;Patch #18822 - Cria&#231;&#227;o de metodos para que o select_estado funcione com o form_for.&lt;/h3&gt;

&lt;p&gt;Esse patch foi enviado pelo Rafael Cardoso e &#233; bastante pertinente s&#243; que n&#227;o foi aceito ainda pois o patch foi gerado de forma incorreta.
Ele j&#225; fez contato comigo e vai enviar o patch correto em breve.&lt;/p&gt;

&lt;p&gt;Queria agradecer aos dois pela colabora&#231;&#227;o constante. J&#225; perdi a conta de quantas vezes aceitei c&#243;digo deles.&lt;/p&gt;</description>
      <pubDate>Tue, 25 Mar 2008 05:44:23 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:c3fc9845-bcb4-449e-85e5-5a03ce77bdb2</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/03/25/brazilian-rails-patch-aceito</link>
      <category>brazilianrails</category>
      <category>rails</category>
      <category>ruby</category>
      <category>audit</category>
    </item>
    <item>
      <title>Brazilian Rails API</title>
      <description>&lt;p&gt;Agora a API do plugin &lt;a href="http://brazilian-rails.rubyforge.org/api"&gt;Brazilian Rails&lt;/a&gt; est&#225; hospedada no &lt;a href="http://rubyforge.org"&gt;RubyForge.org&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;O endere&#231;o &#233;: &lt;a href="http://brazilian-rails.rubyforge.org/api"&gt;http://brazilian-rails.rubyforge.org/api&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dentro de alguns dias teremos um site com uma documenta&#231;&#227;o mais completa do plugin. Ser&#225; uma p&#225;gina semelhante a do nosso outro plugin, o &lt;a href="http://integration.rubyforge.org/"&gt;Integration&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Wed, 19 Mar 2008 16:10:58 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:b990c576-ccc5-43fc-a100-42be3eca264e</guid>
      <author>Marcos Tapaj&#243;s</author>
      <link>http://blog.improveit.com.br/articles/2008/03/19/brazilian-rails-api</link>
      <category>brazilian_rails</category>
      <category>rails</category>
      <category>plugin</category>
    </item>
    <item>
      <title>Onde foram parar aqueles caras da Improve It?</title>
      <description>&lt;p&gt;H&#225; pouco mais de dois meses n&#243;s decidimos &lt;a href="http://blog.improveit.com.br/articles/2007/12/19/novos-rumos-em-2008"&gt;mudar de rumos&lt;/a&gt; e deixar os servi&#231;os de consultoria de lado. De l&#225; para c&#225;, estamos bem quietos. Afinal, o que anda acontecendo por aqui? Resumidamente, resolvemos come&#231;ar nossa jornada resolvendo um problema bem concreto, para ent&#227;o come&#231;ar a trabalhar no nosso primeiro produto. &lt;/p&gt;

&lt;h1&gt;Problema&lt;/h1&gt;

&lt;p&gt;A gente acha que bons produtos s&#227;o extra&#237;dos de projetos reais, que resolvem o problema de algu&#233;m e podem ser re-estruturados para resolver o problema de muitos. Sendo assim, ainda em dezembro, na mesma &#233;poca que anunciamos nossa sa&#237;da do mercado de consultoria, come&#231;amos a trabalhar para um cliente. Trata-se de um neg&#243;cio pequeno, por&#233;m extremamente bem sucedido, que atua em um ramo que movimenta uma boa grana. Ou seja, o neg&#243;cio &#233; pequeno, mas h&#225; dinheiro circulando o tempo todo. Por enquanto, n&#227;o iremos revelar nem quem &#233; o cliente e nem qual &#233; a &#225;rea de neg&#243;cio, mas, para facilitar a hist&#243;ria que vem a seguir, vou dar um nome fict&#237;cio ao nosso cliente. Vamos supor que chama-se J&#250;lia.&lt;/p&gt;

&lt;p&gt;J&#250;lia tinha um site. N&#227;o era dos melhores, mas era toler&#225;vel. Era parecido com muitos outros de pessoas que atuam no mesmo ramo. Este ramo &#233; interessante porque a maioria dos sites &#233; horr&#237;vel e partem de uma premissa que, na nossa opini&#227;o, &#233; profundamente equivocada. Nossa miss&#227;o era dar um novo site &#224; J&#250;lia. Mas, n&#227;o apenas isso. Este site teria que ter algumas funcionalidades que poderiam ajud&#225;-la a acelerar seus processos. Ou seja, h&#225; um aspecto institucional, de apresentar o trabalho e outro funcional muito forte e, tipicamente, mal resolvido. Resolvemos tratar deste &#250;ltimo de maneira inovadora, mas n&#227;o foi s&#243; a&#237; que decidimos inovar. Tamb&#233;m quer&#237;amos quebrar a premissa fundamental que rege a maioria dos sites deste ramo. &lt;/p&gt;

&lt;h1&gt;Primeiro Ato&lt;/h1&gt;

&lt;p&gt;Dividimos o projeto em duas partes, que vou chamar de primeiro ato e segundo ato. O primeiro ato foi implementado em pouco mais de um m&#234;s e colocado no ar por volta do dia 10 de fevereiro de 2008. Na equipe, &lt;a href="http://www.improveit.com.br/vinicius"&gt;eu&lt;/a&gt;, o &lt;a href="http://www.improveit.com.br/tapajos"&gt;Tapaj&#243;s&lt;/a&gt; e o &lt;a href="http://www.improveit.com.br/leandro"&gt;Leandro&lt;/a&gt; trabalhando nisso em torno de trinta horas por semana.&lt;/p&gt;

&lt;p&gt;Durante o desenvolvimento, estivemos pr&#243;ximos da J&#250;lia o tempo todo. Conversamos muito sobre cada aspecto do sistema e fizemos in&#250;meros experimentos, sobretudo com a interface do usu&#225;rio. Al&#233;m disso, tentamos simplificar tudo que pod&#237;amos. A premissa era: pregui&#231;a &#233; bom! Sim, quando se trata de desenvolvimento de software, h&#225; um certo tipo de "pregui&#231;a" que nos alerta quando estamos fazendo algo de forma excessivamente complicada. Foi esta  pregui&#231;a que nos levou, por exemplo, a n&#227;o usar banco de dados para praticamente nada. A &#250;nica exce&#231;&#227;o &#233; o armazenamento de sess&#245;es. Devido a algumas caracter&#237;sticas do aplicativo, n&#227;o dava para usar sess&#245;es baseadas em cookie.&lt;/p&gt;

&lt;p&gt;&#201; poss&#237;vel fazer um software significativo sem banco de dados? Ou melhor, d&#225; para fazer sem persist&#234;ncia? Neste aplicativo, em particular, n&#227;o dava para fazer sem persist&#234;ncia, mas dava para ficar sem banco de dados. Quer dizer que usamos algo tipo preval&#234;ncia de objetos? N&#227;o exatamente. H&#225; muita informa&#231;&#227;o persistida, mas n&#243;s n&#227;o tivemos que cuidar diretamente desta persist&#234;ncia e isso nos poupou muito trabalho. Os detalhes eu vou ficar devendo, lamentavelmente. Mas, posso dar uma id&#233;ia de n&#250;meros para voc&#234;s. Os dados persistidos podem levar o site a ter uma grande quantidade de p&#225;ginas internas. Neste momento, o sitemap cont&#233;m 15.133 p&#225;ginas. Entretanto, este n&#250;mero &#233; menor que o n&#250;mero real de p&#225;ginas que ele possui. Como ficaria muito custoso gerar um sitemap completo, n&#243;s decidimos fazer um corte. Em todo caso, isso d&#225; uma id&#233;ia da quantidade de dados que s&#227;o persistidos e usados no site, por&#233;m, surpreendentemente, n&#227;o h&#225; banco de dados envolvido! :-)&lt;/p&gt;

&lt;p&gt;H&#225; um detalhe interessante nesta quest&#227;o. Se h&#225; tantos dados, como a J&#250;lia faz para cadastrar estes dados e mant&#234;-los? Boa pergunta. N&#227;o d&#225; para explicar aqui como isso &#233; feito, mas basta dizer que sim, h&#225; uma &#225;rea administrativa, onde ela manipula todos os dados com uma interface bacana. Mas, a melhor parte da hist&#243;ria &#233; que n&#243;s n&#227;o tivemos que fazer isso, o que, considerando a sofistica&#231;&#227;o da aplica&#231;&#227;o, explica como fizemos tudo em pouco mais de um m&#234;s.&lt;/p&gt;

&lt;h3&gt;Qualidade&lt;/h3&gt;

&lt;p&gt;Linhas de c&#243;digo n&#227;o indicam quase nada isoladamente, mas, quando usadas em certas compara&#231;&#245;es, servem para dar uma id&#233;ia de caracter&#237;sticas do projeto. At&#233; o momento, temos 742 linhas de c&#243;digo na aplica&#231;&#227;o e 1934 linhas de specs. Isso significa que temos 2.6 linhas de spec para cada linha de c&#243;digo da aplica&#231;&#227;o. Ali&#225;s, n&#227;o h&#225; uma &#250;nica linha de c&#243;digo da aplica&#231;&#227;o que n&#227;o receba a visita de pelo menos um spec. Ou seja, nossa cobertura de c&#243;digo pelos testes &#233; de 100%, como em todos os nossos projetos. Al&#233;m dos specs, temos in&#250;meros testes de aceita&#231;&#227;o no Selenium que totalizam 2136 checagens. Estes &#250;ltimos testes consomem, em m&#233;dia, de 5 a 8 minutos para executar e s&#227;o executados sempre que fazemos uma integra&#231;&#227;o (com o plugin &lt;a href="http://integration.rubyforge.org"&gt;integration&lt;/a&gt;). Estes n&#250;meros mostram que temos uma preocupa&#231;&#227;o significativa com a quest&#227;o da qualidade. &lt;/p&gt;

&lt;p&gt;Al&#233;m dos testes automatizados, n&#243;s tamb&#233;m realizamos testes manuais em cinco navegadores: IE6, IE7, Firefox, Opera e Safari. Estes testes t&#234;m o objetivo de inspecionar visualmente a parte do design, j&#225; que este &#233; um terreno ainda complicado para os testes automatizados. Qualquer mudan&#231;a no site leva, inevitavelmente, a testes manuais nestes navegadores, al&#233;m dos automatizados. Em todo caso, h&#225; um tipo de checagem automatizada que podemos fazer para a parte do design. Trata-se das valida&#231;&#245;es da W3C. O aplicativo passa nas valida&#231;&#245;es da W3C. Desde o in&#237;cio do projeto o &lt;a href="http://www.improveit.com.br/leandro"&gt;Leandro&lt;/a&gt;, sobretudo, tem demonstrado muita preocupa&#231;&#227;o em assegurar que o aplicativo respeite todos os web standards. &lt;/p&gt;

&lt;p&gt;Os n&#250;meros relacionados aos testes s&#227;o elevados, mas, quando o assunto &#233; gest&#227;o de bugs, os n&#250;meros j&#225; n&#227;o s&#227;o t&#227;o expressivos. Para come&#231;o de conversa, n&#227;o temos nem mesmo um sistema de gest&#227;o de bugs. Pois &#233;, que desorganizados n&#243;s somos, n&#233;? Nenhum sistema para gerenciar chamados e controlar os bugs. A sim, agora lembrei o porqu&#234; disso. N&#227;o tivemos nenhum relato de bug desde que o sistema foi ao ar! E n&#227;o foi por falta de uso. Ent&#227;o, acho que d&#225; para continuar sem gest&#227;o de bugs. Mas, garanto que seria imposs&#237;vel fazer isso sem a rela&#231;&#227;o quase paran&#243;ica que n&#243;s temos com os testes.&lt;/p&gt;

&lt;p&gt;Sendo bem honesto, a falta de relatos de bugs n&#227;o significa que eles n&#227;o existam. Significa apenas que n&#227;o foram descobertos ainda. De fato, havia alguns que n&#243;s pr&#243;prios conseguimos detectar depois de colocar o sistema no ar. Nenhum deles era grave e talvez ningu&#233;m nem tenha chegado a passar por eles. Mas, n&#243;s corrigimos assim que identificamos. Em todo caso, j&#225; faz v&#225;rios dias que n&#227;o conseguimos detectar nada novo e continuamos sem nenhum relato de bug, apesar de termos uma utiliza&#231;&#227;o crescente da aplica&#231;&#227;o.&lt;/p&gt;

&lt;h3&gt;Hospedagem e Deployment&lt;/h3&gt;

&lt;p&gt;Estamos usando o VPS de 512MB da &lt;a href="http://www.slicehost.com"&gt;SliceHost&lt;/a&gt;. At&#233; o momento, o servi&#231;o deles tem sido perfeito. A m&#225;quina &#233; muito r&#225;pida e est&#225;vel. De fato, ela &#233; superestimada para as necessidades desta aplica&#231;&#227;o. Mas, preferimos que seja assim. N&#243;s fizemos in&#250;meros testes de desempenho com o &lt;a href="http://www.hpl.hp.com/research/linux/httperf/"&gt;Httperf&lt;/a&gt; antes de lan&#231;ar o site e eles demonstraram que o site tem um tempo de resposta excepcional, mesmo quando a carga &#233; muito elevada. Parte disso, naturalmente, tem a ver com o trabalho cuidadoso que fizemos na parte de caching.&lt;/p&gt;

&lt;p&gt;Este aplicativo tem a propriedade de n&#227;o ter modifica&#231;&#245;es muito freq&#252;entes, embora tenha uma grande quantidade de dados. Em torno de 90% do site pode se beneficiar do cache mais eficaz que temos no &lt;a href="http://www.rubyonrails.org"&gt;Rails&lt;/a&gt;, que &#233; o cache de p&#225;gina. Sendo assim, estamos usando cache de p&#225;gina na maior parte do site e o resultado n&#227;o poderia ser melhor. Os 10% restantes felizmente representam as funcionalidades menos usadas, embora tenham sido as mais trabalhosas para implementar. &lt;/p&gt;

&lt;p&gt;Quanto ao application server, inicialmente pensamos em usar o &lt;a href="http://nginx.net/"&gt;nginx&lt;/a&gt; com o &lt;a href="http://mongrel.rubyforge.org"&gt;Mongrel&lt;/a&gt;. Mas, antes de tentar esta alternativa, lembrei da apresenta&#231;&#227;o que considerei a mais interessante no Minas on Rails e no Rio on Rails. Foi a do Eduardo Rocha, do &lt;a href="http://www.ocurioso.com"&gt;O Curioso&lt;/a&gt;. Uma das coisas que me chamou a aten&#231;&#227;o foi que ele disse que usava um tal de &lt;a href="http://litespeedtech.com"&gt;LiteSpeed&lt;/a&gt; e que recomendava. At&#233; ent&#227;o, eu jamais tinha ouvido falar do &lt;a href="http://litespeedtech.com"&gt;LiteSpeed&lt;/a&gt;. Conversei com o Eduardo antes de colocar a aplica&#231;&#227;o no ar e ele refor&#231;ou a prefer&#234;ncia pelo &lt;a href="http://litespeedtech.com"&gt;LiteSpeed&lt;/a&gt; e a recomenda&#231;&#227;o. Resolvemos experimentar e n&#227;o poder&#237;amos estar mais felizes. O &lt;a href="http://litespeedtech.com"&gt;LiteSpeed&lt;/a&gt; cuida de tudo e &#233; muito f&#225;cil de usar. Atua como WebServer, Application Server e ainda distribui a carga para v&#225;rias inst&#226;ncias do &lt;a href="http://www.rubyonrails.org"&gt;Rails&lt;/a&gt;. No nosso caso, est&#225; configurado para usar at&#233; dez inst&#226;ncias simultaneamente.&lt;/p&gt;

&lt;p&gt;O &lt;a href="http://litespeedtech.com"&gt;LiteSpeed&lt;/a&gt; &#233; muito est&#225;vel, leve e r&#225;pido. No lado web server, &#233; mais r&#225;pido e mais leve que o Apache. A integra&#231;&#227;o com o &lt;a href="http://www.rubyonrails.org"&gt;Rails&lt;/a&gt;, atrav&#233;s do LSAPI gera um desempenho superior ao do &lt;a href="http://mongrel.rubyforge.org"&gt;Mongrel&lt;/a&gt;. A &#250;nica coisa que ainda n&#227;o entendi &#233; por que tanta gente usa o &lt;a href="http://mongrel.rubyforge.org"&gt;Mongrel&lt;/a&gt; quando poderia usar o &lt;a href="http://litespeedtech.com"&gt;LiteSpeed&lt;/a&gt; que &#233; melhor em todos os aspectos que vimos at&#233; o momento. A sim, ele n&#227;o &#233; open source, mas n&#227;o &#233; necess&#225;rio pagar por nenhuma licen&#231;a, a menos que o site tenha que responder a um n&#250;mero superior a 150 requisi&#231;&#245;es por segundo, o que ainda n&#227;o &#233; o nosso caso.&lt;/p&gt;

&lt;p&gt;Fizemos testes de desempenho com &lt;a href="http://www.hpl.hp.com/research/linux/httperf/"&gt;Httperf&lt;/a&gt; e conseguimos simular at&#233; 4000 requisi&#231;&#245;es por segundo para p&#225;ginas em cache. Infelizmente n&#227;o sabemos o limite real que o servidor ag&#252;entaria porque acima deste valor, a m&#225;quina que simula os acessos passa a operar com 100% de consumo de CPU, devido &#224; grande quantidade de threads que s&#227;o criadas para o teste. At&#233; 4000 requisi&#231;&#245;es por segundo, o servidor n&#227;o chegava a consumir sequer 50% da CPU.&lt;/p&gt;

&lt;h1&gt;Segundo ato&lt;/h1&gt;

&lt;p&gt;No momento, estamos trabalhando na segunda parte do projeto que deve ser colocada em produ&#231;&#227;o na pr&#243;xima semana. A partir da&#237;, a J&#250;lia segue seu caminho e n&#243;s seguimos o nosso. Passaremos a trabalhar para generalizar o aplicativo que fizemos para ela. O objetivo, naturalmente, ser&#225; permitir que o outros pequenos neg&#243;cios, no mesmo ramo, possam fazer uso do mesmo aplicativo.&lt;/p&gt;

&lt;h1&gt;Resultados&lt;/h1&gt;

&lt;p&gt;Assim que o novo site da J&#250;lia foi ao ar, ela come&#231;ou a receber in&#250;meros coment&#225;rios de clientes e pessoas do mesmo ramo elogiando o trabalho. Houve pouqu&#237;ssima cr&#237;tica. As apostas que n&#243;s fizemos se revelaram certeiras. Agora, in&#250;meros colegas dela, da mesma &#225;rea de neg&#243;cio e correlatas, perguntam-lhe quem fez o site e querem ter um igual. Que legal! :-) &#201; claro que n&#243;s queremos atender a todos eles, mas ainda n&#227;o &#233; o momento. N&#227;o queremos fazer um site para cada pessoa. Queremos que todos usem um produto bem definido, que seja f&#225;cil para eles usarem e, sobretudo, que nos permita incorporar novos clientes com rapidez e facilidade. Por conta disso, a J&#250;lia tem um acordo de sigilo conosco que a impede de dizer quem fez. Como n&#227;o queremos ningu&#233;m nos fazendo perguntas sobre o site dela antes da hora, nem ela conta quem fez, nem eu conto para voc&#234;s o que n&#243;s fizemos. E assim n&#243;s vamos ficar por mais alguns meses, beleza? :-)&lt;/p&gt;

&lt;p&gt;Uma das coisas que n&#243;s mais gostamos de saber &#233; que o novo site est&#225; rendendo bons frutos para a J&#250;lia. Duas coisas nos chamaram a aten&#231;&#227;o em particular. A primeira &#233; que ela relatou que o n&#250;mero de pedidos di&#225;rios de or&#231;amento para seus servi&#231;os cresceu mais de cinco vezes desde que o site foi colocado no ar. Ela agora gasta muito mais tempo respondendo emails, mas este n&#227;o &#233; um problema assim t&#227;o ruim, n&#233;? :-) A outra coisa legal &#233; que ela disse que agora os clientes j&#225; chegam respeitando-a muito mais. Eles olham o site e concluem que est&#227;o lidando com uma profissional de alt&#237;ssimo n&#237;vel, o que &#233; mais do que verdade. &lt;/p&gt;

&lt;p&gt;Estamos animados e continuamos trabalhando bastante. Por isso que n&#227;o tem dado tempo para escrever muito. Felizmente, ontem conseguimos publicar o plugin &lt;a href="http://integration.rubyforge.org"&gt;integration&lt;/a&gt; e tem um outro que est&#225; no forno. Espero que possamos lan&#231;ar em breve. Tem muita coisa legal vindo por a&#237;.&lt;/p&gt;</description>
      <pubDate>Thu, 13 Mar 2008 08:55:52 -0300</pubDate>
      <guid isPermaLink="false">urn:uuid:2c407262-a129-4939-adce-8b99e6d02bea</guid>
      <author>Vinicius Manh&#227;es Teles</author>
      <link>http://blog.improveit.com.br/articles/2008/03/13/onde-foram-parar-aqueles-caras-da-improve-it</link>
      <category>produto</category>
      <category>rails</category>
    </item>
  </channel>
</rss>
