Sem tempo suficiente

{ June 29th, 2010 }


cmilfont

Autor: cmilfont

Recentemente, em um determinado projeto, tínhamos uma semana para disponibilizar uma versão e uma timeline definida por motivos externos que não poderíamos furar. O problema era que toda modificação gerava ainda mais medo por conta da baixa cobertura de testes, praticamente estavam codificando e corrigindo nessa altura do campeonato.

Eu radicalmente sugeri um grande refactoring para corrigir nossa bateria de testes, uma parada faltando apenas uma semana para entrega, mas só assim voltaríamos a trabalhar na entrega das features.

Nesse momento, o clássico “Não temos tempo para isso” surgiu das profundezas do inferno.

Fiquei sozinho nessa decisão, o time inteiro foi contra. Na defesa da solução apresentada eu falei: “Vocês podem se enganar imaginando que podem entregar essa release em uma semana com a qualidade do código existente que vocês sabem que vai de mal a pior ou podem trabalhar para corrigir esses problemas e entregar o possível, mas funcionando”.

Sabemos da importância de testes, todas as metodologias os cobra obrigatoriamente, então se você não testa, você está errado em todas as metodologias. O problema sempre é a desculpa da timeline e quanto mais vai se aproximando mais desculpas procuramos encontrar para esconder as deficiências. Como nesse caso não tínhamos Test First, os problemas vão se empilhando no final e se tornam mais difíceis de serem detectados.

Por sorte, minha sugestão acabou sendo acatada, apesar de ser apenas um consultor no projeto, portanto uma galinha e não porco.

De onde nascem essas desculpas?

Coragem é um dos valores do XP, é importante enfrentarmos esse tipo de situação que descrevi, na vida real isso quase nunca é possível porque essas arquiteturas flácidas ou códigos mal cheirosos não nascem do dia para o outro e vão se acumulando.

O projeto que descrevi era um projeto novo, tecnologias fresquinhas e um time modernoso. Imagina agora se você está em uma corporação que usa um processo cascata, todo amarrado, criando documentos UML desnecessários no EA, struts 1 como framework, CVS como controle de versão do código [quando há! Sim, em pleno 2010 ainda há quem não use nenhum], o código de banco de dados cheio de procedures e tantas modernidades da década de 80.

Então, acha que só coragem basta?

Em muitas oportunidades o custo de mudanças ou simplesmente “fazer o que se tem que fazer” não se pagará nem a médio prazo, nessas horas convencer já não basta. É muito difícil você convencer a alta direção que deve jogar fora um determinado projeto e começar do zero, ou modificar toda a infraestrutura existente.

A degradação de um software nasce de pequenos problemas que se acumulam, no final há tanto para se fazer que ninguém mais tem coragem para isso.

Socorro, Milfont!

Recebo constantemente pedido de socorro de pessoas que me conhecem das comunidades que participo como XPCE, GURU-CE, JAVA-CE, entre outras. Geralmente são funcionários que se encontram nessa situação que citei anteriormente, com projetos muito defasados e problemáticos.  O pedido é sempre o mesmo, querem que eu vá lá dizer para a alta direção o que eles [funcionários] já sabem. Só que isso não basta, o movimento tem que começar por lá.

Em reunião com a turma da TriadWorks, temos discutido isso já há muito tempo e acabamos preparando um serviço de resgate aos clientes para contornar esse problema. A proposta é envolver as pessoas desses clientes, dar coragem e ânimo nelas para começarem a resolver o problema.

Resolvemos começar com nossos próprios clientes, sim, dá preferência a quem tem contrato conosco e depois verificar como abrir para a comunidade.

Então, esse envolvimento nós demos o codinome de “AvoidNotEnoughTime” e consiste basicamente em um conjunto de ações/eventos  com os funcionários dessas empresas para dar essa força necessária para anular o NotEnoughTime na base. É um movimento de baixo pra cima, roots, serão desde Coding Dojos, Code Retreat, Code Jam, Hack Days, Lightning Talks, Open Space ou um formato adequado a um determinado problema que identificarmos.

Nós não vamos cobrar a mais dos clientes por isso, aliás, eles nem foram avisados e não terão controle sobre o projeto, nós que decidimos quando, como e com quem faremos justamente para evitar sabotagem ou direcionamento.

Sem planejamento nem nada, resolvemos iniciar mesmo assim, domingo passado [27/06/2010] realizamos um Git Session onde eu [@cmilfont], @triadworks representada por @handersonbf, @rponte e @carlosatilabreu, recebemos funcionários de clientes nossos. @jeffersongirao da TubForm, @rodrigogalba da Casa Magalhães e @rodrigodealer da Fortes Informática.

O que vocês ganham com isso?

Resolvemos fazer um Git Hack Session devido alguns de nossos clientes usarem CVS e SVN. O tempo perdido resolvendo problemas de repositório como merges e bobagens simples causam um prejuízo enorme, as desculpas para mudarem cai sempre no “não temos suficiente” ou “depois fazemos quando terminar esse projeto”.

Então cada ponto de dificuldade que um time enfrenta e observarmos que se repete nos demais clientes, vamos organizar ações para envolver essa turma afim de anular essas desculpas. Treinar multiplicadores em todos os princípios.

No caso do Jefferson Girão, que trabalha também para a Hoodiny, veio mais para nos auxiliar, já que está mestre no uso do git no meu cliente Tubform [uma das maiores indústrias do Nordeste].

Dessa forma nosso trabalho de consultoria será facilitado e no mínimo já faríamos esses eventos internamente, então unimos o útil ao agradável.

Se você gostaria de participar de algum desses eventos mesmo não sendo funcionário de cliente nosso, mande um email para mim [cmilfont@gmail.com] e tentaremos incluir sempre quando puder. Domingo agora surgiu um desfalque, até twittei convocando alguém que estivesse disponível, mas foi em cima da hora.

Começou #gitsession on Twitpic

Posted in Engenharia de Software, Melhores práticas, Metodologia, Métodos Ágeis, Test Driven, XP ~ 6 Comments

JQuery e conflitos

{ June 28th, 2010 }


cmilfont

Autor: cmilfont

Creio que todo mundo já conheça a função noConflict do JQuery para evitar conflitos com outros frameworks que utilizam a variável dóllar ($). JQuery é sem dúvidas o melhor framework javascript para manipulação DOM e não há motivos e nem desculpas para não o usar, principalmente com essa resolução de conflitos.

Tenho refatorado alguns códigos javascript e o pessoal tem resolvido o conflito de forma confusa e misturando código de dois framework, inclusive código DOM nativo. A documentação recomenda, como uma opção, atribuir o resultado da função noConflict a uma variável e ela será o seu objeto JQuery.

Imagina que você tem Prototype e Jquery na mesma aplicação como no codigo abaixo:

$J = jQuery.noConflict();

//codigo prototype
$("id_de_algum_elemento").hide();
//codigo jquery em seguida
$J("#id_do_elemento").load("caminho.html");
view raw gistfile1.js This Gist brought to you by GitHub.

A legibilidade vai ser horrível para manutenção desse código porque você vai ficar com códigos misturados com sintaxes e estilos diferentes, a medida que isso vai crescendo a manutenção vai ficando impossível.

Minha sugestão é utilizarem Closure e Currying para resolver o conflito, isolar o código e deixar bem mais claro. Se ler a documentação lá do noConflict tem exemplo como o código abaixo.

/* essa chamada evita o conflito com outros
frameworks que usam dollar ($) */
jQuery.noConflict();

(function($) {
   // Seu código jquery vai aqui
  $("#id_do_elemento").load("caminho.html");
})(jQuery);

//codigo prototype
$("id_de_algum_elemento").hide();
//...

view raw gistfile1.js This Gist brought to you by GitHub.

Se você preferir deixar claro a diferença entre os frameworks pode continuar a usar outra variável no lugar do $, mas a idéia é isolar o código de cada framework.

Posted in Frameworks, JavaScript, Jquery, Melhores práticas, Web Development ~ No Comments

Setup do Sunspot-rails no Rspec

{ June 23rd, 2010 }


cmilfont

Autor: cmilfont

Tínhamos um problema nos testes unitários por débito técnico [na verdade desleixo mesmo] com o setup do Rspec e Sunspot-rails em determinado projeto. O problema era que mesmo para executar um simples teste unitário, levantávamos o Sunspot no spec_helper.rb.

Resolvi refatorar isso, acabei descobrindo no before/after do Spec::Runner.configure algo que eu não usava e que já existia desde o rspec “1.1.12 / 2009-01-11″, pelo que percebi no changelog.

O que fiz e parece bobo é separar pelo tipo (type) integration a subida de uma instancia real do Sunspot e agora dá para usar a estrutura de Rspec que o Sunspot disponibiliza para meus testes unitários.

#arquivo spec_helper.rb

ENV["RAILS_ENV"] ||= 'test'

require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment'))

require 'spec/autorun'
require 'spec/rails'
require 'rake'
require 'ruby-debug' unless RUBY_VERSION > '1.9'
require 'sunspot/rails/tasks'
require 'authlogic/test_case'
require 'sunspot/rails/spec_helper'

require 'database_cleaner'

#observe aqui que eu criei uma pasta support porque guardo algumas confs em arquivos contidos nela
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}

Spec::Runner.configure do |config|
  config.use_transactional_fixtures = true
  config.use_instantiated_fixtures = false
  config.fixture_path = RAILS_ROOT + '/spec/fixtures/'

  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

  [:model, :helper, :controller].each {|type|
    config.before(:each, :type => type) do
      ::Sunspot.session = ::Sunspot::Rails::StubSessionProxy.new(::Sunspot.session)
    end
    config.after(:each, :type => type) do
      ::Sunspot.session = ::Sunspot.session.original_session
    end
  }

  config.before(:all, :type => :integration) do
    JojobaSunspot.new.start
  end
  config.after(:suite) do
    JojobaSunspot.new.stop
  end

end

Inspirado nesse post, eu adaptei para o código que uso ao subir o sunspot com linha de comando para os testes de integração. Observe no código anterior que importo configurações da pasta support, inclusive a classe JojobaSunspot, usada no after e before de integration.

require "net/http"

class JojobaSunspot

  def start
    @started = Time.now
    up_sunspot if starting
    up
  end

  def stop
    system("sunspot-solr stop --pid-dir=/tmp/pids") unless starting
  end

  private
  def port
    Sunspot::Rails::Server.new.port
  end

  def up_sunspot
    system("sunspot-solr start -p 8981 -d /tmp/solr_data_test --pid-dir=/tmp/pids --log-file=/tmp/solr_log_test.log --log-level=INFO")
  end

  def up
    while starting
      puts "Sunspot server is starting..."
    end
    puts "Sunspot server took #{'%.2f' % (Time.now - @started)} sec. to get up and running. Let's Jojoba!"
  end

  def starting
    begin
      sleep(1)
      request = Net::HTTP.get_response(URI.parse("http://localhost:#{port}/solr/"))
      false
    rescue Errno::ECONNREFUSED
      true
    end
  end

end

Desde que colocamos testes de integração o tempo de execução da bateria subiu muito, provocamos um setup ineficiente e desnecessário para os testes unitários. Fica a dica para quem passar pelo mesmo problema.

Posted in Rails, Rspec, Ruby, Sunspot ~ 1 Comment