Colecionar débitos técnicos não é maneiro não
Depois de um tempo sem postar, lá vamos nós de novo ;). Quem assina o feed provavelmente recebeu uma atualização sobre esse post antes do que devia! Eu esqueci de marcar ele como rascunho e aí ficou a manhã toda o post publicado apenas com um smile. Depois do furo não tive outra opção a não ser escrever o post até o final o mais rápido possível.
Após participar de inúmeros projetos e de formas de gerencia sobre os projetos tenho chegado a algumas conclusões sobre a questão dos débitos técnicos, refatoração e testes.
No começo do V2V, projeto do Portal do Voluntário, muito código novo foi escrito em cima de um código que usamos como base. Toda alteração de código era devidamente testada usando Rspec. Por considerar que alguns testes não eram muito importantes, as vezes eu deixava a spec como pending para fazer uma posterior implementação. Assim podia entregar as coisas um pouco mais rápido. De fato isso aconteceu em apenas uma meia dúzia de specs, ainda bem!
O fato é que hoje, 9 meses depois do sistema estar em produção, e já com 3 grandes clientes utilizando – rumando para o quarto – a mesma meia dúzia de specs continuam como pending.
Esse quadro é comum acontecer também em relação aos débitos técnicos dos projetos. O que é um débito técnico? É um empréstimo que você faz, inserindo alguma coisa mal feita no sistema – leia-se POG – com objetivo de ganhar um pouco de tempo naquele momento. É um empréstimo pois ele pode ser comparado ao empréstimo bancário. Você pega um dinheirinho e aquilo tem um juros. Quanto mais tempo você leva pra devolver aquele dinheiro pro banco mais você paga de juros. No nosso caso quanto mais tempo levamos para remover os débitos técnicos mais tempo perdemos por causa dele.
Assim como as minhas 6 specs pendentes, é comum que débitos técnicos se prolonguem por toda a vida do projeto causando muito mais transtornos do que seria corrigi-los na época em que isso faria atrasar a entrega em apenas um dia.
Em alguns dos projetos que trabalhei às vezes separávamos uma semana para “arrumar a casa”. Ou seja: quitar os débitos técnicos que foram se criando com objetivo de fazer entregas mais rápidas. Uma semana de projeto no lixo sem nenhuma funcionalidade nova! Essa não é a forma correta de fazer.
Se você estimou o desenvolvimento de uma funcionalidade em uma hora e tem um débito técnico te atrapalhando que vai fazer você demorar duas horas a mais para quitá-lo, essa é a hora de quitá-lo. Não faça mais uma POG! Pegar mais um empréstimo nessa hora vai fazer você pagar juros sobre juros e isso irá te atrapalhar mais na semana seguinte.
A refatoração é um processo contínuo e on the fly.
2 comentários : 17.08.2009 04:09 PM
Como vocês fazem o "describe" das suas specs?
Isso pra mim sempre foi uma dúvida ao usar o rspec. Realmente não há forma correta. É uma opção pessoal no caso de um projeto particular ou de decisão em conjunto no caso de um projeto onde vários desenvolvedores participam.
Mas o fato é que eu nunca adotei nenhum padrão para isso. É uma coisa que tem me deixado um pouco incomodado. Em alguns modelos sigo o padrão de um describe para cada método, em outros segui padrões ligeiramente diferentes, como por exemplo testes relacionados a attributos em um describe, relacionamentos em outro describe e assim por diante. Ou seja, não há padrão. Há tempos atrás ouvi uma frase que nunca esqueci:
Quando dois padrões existem, não há padrão.
No Lucidus usávamos Test::Unit(quando o projeto começou o rspec ainda era muito pouco difundido) então o “padrão” para nós era pelo menos colocar os testes relativos juntos. Então os testes relativos a um mesmo método normalmente estavam juntos, em um “bloco”, um abaixo do outro. O rspec nos permite um pouco mais de organização. Mas fazer essa organização extra através dos describes proporciona algum benefício?
Então seguindo a idéia… nós precisamos discutir testes.
Qual opnião de vocês? Como vocês organizam seus describes? E o que vocês escrevem nele?
3 comentários : 28.11.2008 03:18 AM
Um "setup" global para todas as suas specs
Ficou bem difundido no rspec a forma em como fazer o setup antes das specs executarem, assim como existe também no Test::Unit.
describe Act do
before(:each) do
(...)
end
it "should have many persons associated" do
(...)
end
end
Eu estava precisando fazer o setup para todas as minhas specs (do planeta :), então descobri uma forma que está mal documentada(pelo menos eu não achei bom), mas é super simples de usar. É só editar o spec/spec_helper.rb e adicionar dentro do bloco:
Spec::Runner.configure do |config|
(...)
end
O seguinte:
config.before(:each) do
your_global_setup_here
end
Você também pode executar o setup somente para os controllers, models ou helpers assim:
config.before(:each, :behaviour_type => :controller) do
your_global_controllers_setup_here
end
Ou
config.before(:each, :behaviour_type => :helper) do
your_global_helpers_setup_here
end
Ou
config.before(:each, :behaviour_type => :model) do
your_global_models_setup_here
end
Como se chama o “setup” no bdd? É setup mesmo?
4 comentários : 27.11.2008 02:50 AM
Fazendo o will_paginate traduzir o "Previous" e "Next"
Eu precisei traduzir para várias línguas os links de “Previous” e “Next” do will_paginate, mas não seria nada dry passar os parâmetros em todas as chamadas a will_paginate(). Outra solução seria criar um método helper que faria a chamada ao will_paginate() passando os parâmetros e nas minhas views eu chamaria esse helper no lugar de chamar will_paginate(). O problema é que sempre que fosse criada uma nova tela com paginação a pessoa teria que lembrar de chamar o método helper e não chamar o will_paginate() diretamente.
Então pra mim a melhor solução foi criar uma extensão, que deixa tudo transparente. Eu coloquei em /lib dentro do projeto rails.
module WillPaginate
module ViewHelpers
def will_paginate_with_translate(collection = nil, options = {})
options, collection = collection, nil if collection.is_a? Hash
options.merge!(:prev_label => _("« Previous"), :next_label => _("Next »"))
if collection
will_paginate_without_translate(collection, options)
else
will_paginate_without_translate(options)
end
end
alias_method_chain :will_paginate, :translate
end
end
O método _() que é chamado é o método que faz a tradução no plugin de localização que estou utilizando, você deve alterar para a forma como você faz a localização no seu projeto. Também criei as specs para assegurar o funcionamento:
require File.dirname(__FILE__) + '/../spec_helper'
describe WillPaginate::ViewHelpers do
describe "will_paginate translations" do
before(:each) do
@expected = 'paginate_mock'
@model = mock('model-mock')
@translation_options = {:prev_label => _("« Previous"), :next_label => _("Next »")}
@options = {:option1 => '1', :option2 => '2', :next_label => 'next-fake'}
end
it "should will_paginate only with translations" do
helper.should_receive(:will_paginate_without_translate).with(@translation_options).and_return(@expected)
helper.will_paginate == @expected
end
it "should will_paginate with @model parameter" do
helper.should_receive(:will_paginate_without_translate).with(@model, @translation_options).and_return(@expected)
helper.will_paginate(@model) == @expected
end
it "should will_paginate with @model parameter and options" do
helper.should_receive(:will_paginate_without_translate).with(@model, @options.merge(@translation_options)).and_return(@expected)
helper.will_paginate(@model, @options) == @expected
end
end
end
Espero que seja útil para alguém ;)
4 comentários : 24.11.2008 12:52 PM




