Fork me on GitHub

Keep Learning Conhecimento nunca é o bastante




Me recomende

Flickr
Ver todas »
Amsterdam - Oude KerkAmsterdam - Oude KerkAmsterdamAmsterdamAmsterdam - St. NicolaaskerkAmsterdam - Royal PalaceAmsterdam - Oude KerkAmsterdam - Oude Kerk

Utilizando rack-debug para debugging com Passenger

Desenvolver aplicações Rails utilizando o Phusion Passenger (principalmente no Mac OS X com o Passenger preference pane) é muito prático. Porém, uma coisa que logo senti falta foi a possibilidade de utilizar a gem ruby-debug quando precisava de breakpoints para debuggar o código.

Uma maneira de conseguir isso é através da gem/plugin rack-debug. Para utilizá-la, segui os passos abaixo.

1. Instalação

 $ script/plugin install git://github.com/ddollar/rack-debug.git
 
 # config/environments/development.rb
 config.middleware.use "Rack::Debug"

2. Chamar o debugger onde necessário:

  def create
    @status = current_user.statuses.create(params[:status])
    debugger
    if @status.valid?
...

3. Conectar-se ao debugger

 # No diretório da aplicação, chamar a task rake
 $ rake debug
 Connected.

4. Ao executar a linha onde o debugger foi chamado, a aplicação para e você tem acesso ao console do debugger

 (rdb:1) p @status
 #<Status id: 231, text: "Testing rack-debug", user_id: 4, ...>

Pronto. Happy debugging! :)

Update: ao chamar a task rake, pode ocorrer um erro com a mensagem “Server is not running or Passenger has spooled down”. Neste caso, reinicie o Apache e tudo deve funcionar normalmente.


Seu chefe é incompetente? A ciência explica!

Pesquisas feitas na Universidade de Catania, na Itália, mostram que, quanto mais promoções, mais incompetente é o profissional. A pesquisa foi feita a partir do chamado Princípio de Peter, formulado pelo psicólogo canadense Laurence J. Peter, com a seguinte frase (original, em inglês): “Every new member in a hierarchical organization climbs the hierarchy until he/she reaches his/her level of maximum incompetence”.

A explicação é simples: no sistema de promoção por mérito, pessoas muito boas em dada especialidade são promovidas para outras áreas, para as quais podem ser menos aptas (claro, isso só ocorre quando a promoção leva o profissional a uma área em que suas habilidades atuais não são fundamentais). Dessa forma, cair nas garras do Princípio de Peter torna-se inevitável, levando a empresa a uma perda geral de eficiência ao longo do tempo.

A solução, segundo os cientistas, é reservar 50% das promoções para os piores profissionais da empresa – a chance de que eles “se encontrem” nos cargos aos quais são promovidos é muito maior.

Que desenvolvedor de software nunca topou com esse tipo de problema? Aquele cara, ótimo desenvolvedor, acaba sendo promovido à gerente (e aceita, seja pela grana, pelo status ou por falta de opção) e é simplesmente um zero à esquerda na função. É claro que isso acontece em qualquer área, mas é nesta em que eu tenho experiência.

Podemos tirar duas lições disso:

  • Se, por ser um ótimo desenvolvedor, você for agraciado com uma promoção para outra área, pense duas vezes antes de aceitar – isso pode significar o fim da sua carreira como profissional competente. Se a empresa não lhe der opção (é bem comum que só se consiga um aumento aceitando uma promoção-bomba dessas), procure outro lugar – quando você realmente é competente, escolhas não faltam.
  • Se você se tornar um empreendedor, primeiro busque ajuda especializada caso não se sinta à vontade com as tarefas necessárias nesse seu “novo cargo”. Você pode ser um ótimo designer com uma ótima ideia, mas isso não quer dizer que será um bom empresário. Além disso, pense bem na política de promoção que vai utilizar se a empresa for bem sucedida. Um exemplo: pode ser muito mais satisfatório recompensar os bons funcionários com melhorias salariais do que promovê-los a cargos para os quais eles não possuem aptidão.

Cuidado com o DRY nos seus testes

Don’t Repeat Yourself é um dos princípios de desenvolvimento de software mais “badalados” nos últimos tempos. O problema é que, como tudo que se torna popular, isso acaba sendo abusado. Numa tentativa de criar código limpo é comum criar código difícil de entender. Isso afeta principalmente os testes.

Testes devem ser extremamente legíveis. Não deve existir sobrecarga cognitiva, isto é, não deve ser necessário entender o código do teste para então entender o comportamento que ele especifica – isso deve ficar claro rapidamente. Exemplos de sobrecarga são a necessidade de “ficar pulando” entre vários arquivos ou “descriptografando” lógica mágica para entender o código do teste.

É fácil, então, identificar dois tipos de recursos que podem causar problemas no entendimento dos testes – há uma tênue linha separando o bom e o mal uso deles: macros e “magia negra” em forma de código Ruby.

Macros devem ser utilizadas com muito cuidado. É interessante utilizar macros que encapsulam código simples para economizar tempo na criação dos testes, como essa macro para especificar ações autenticadas com o Authlogic:

def login_as(user)
  activate_authlogic   #this is from Authlogic::TestCase
  UserSession.create({:email => user.email, :password => user.password})
end

Macros com muito código ou que utilizam outras macros devem ser evitadas.

Um problema provavelmente mais grave é a utlização de algumas técnicas de “magia negra” no código. Aquela técnica super obscura e bacana envolvendo o Enumerable que você viu num blog esses dias não deve ser usada nos testes (nem na lógica de negócios, na minha opinião): foque sempre nos idiomas comuns da linguagem. Por simples falha da minha memória agora, segue um exemplo bobo, mas válido:

# truque menos conhecido
%w(this is a test) * ", "    #=> "this, is, a, test"
 
# idioma comum
%w(this is a test).join(", ")    #=> "this, is, a, test"

Os testes, quando usados corretamente, também são a porta de entrada de novos desenvolvedores ao código já existente na aplicação. Pode ser que sua equipe seja formada por Rubistas experientes que conheçam todos os truques envolvidos, mas a adaptação de um profissional com menos experiência na linguagem pode ser muito facilitada por testes com código simples e altamente legível, mesmo que isso “custe” alguma repetição ou uso de construções mais comuns.

A conclusão é: em todo seu código e principalmente nos testes, evite o uso de macros que escondem muito código ou lógica relevante ao comportamento especificado e também prefira idiomas comuns, mesmo que você saiba técnicas “ninja” da linguagem.


Você confia em métricas?

Usar métricas no seu código é uma boa prática. Existem várias ferramentas que provém métricas muito interessantes e ferramentas, como o metric_fu, que integram várias delas.

No entanto, é preciso ter bastante cuidado. Métricas são como muletas: muito úteis quando você não consegue andar sem a ajuda delas mas, se você utilizá-las sem necessidade, vai enfraquecer suas pernas.

Um bom exemplo disso é uma métrica muito utilizada por quem escreve testes: a cobertura de código. É uma ferramenta muito útil quando é preciso “correr atrás” do prejuízo, isto é, adicionar testes a código sem cobertura. Nesse caso, é prática comum estabelecer uma porcentagem de cobertura a ser atingida dentro de um prazo limitado. Mas, se você pratica BDD/TDD consistentemente e não deixa código importante sem cobertura, é realmente necessário confirmar isso com um gráfico ou uma porcentagem?

O uso e confiança cega em métricas mesmo sem necessidade de um amparo como esse pode levar à má aplicação da técnica do desenvolvimento guiado por testes, já que ela passa a ser baseada em um número artificial – é muito fácil ter 100% de cobertura de código com uma suíte de testes ruim. Antes uma suite boa mas que, conscientemente, não passa por cada linha de código do que uma suite que execute cada linha, mas seja um lixo como especificação e ferramenta de refactoring.

Mais um exemplo de fragilidade fica claro no famoso e cantado aos quatro ventos code to test ratio: ao utilizar um framework de testes verboso, é fácil obter uma razão de linhas de teste por linhas de código muito maior do que utilizando um framework mais compacto ou macros. Me desculpe quem utiliza e divulga esse número como algum indicativo de qualidade, mas essa medida é simplesmente ridícula, além de totalmente ilusória.


Testes envolvendo tempo: usando a gem time-warp

É comum que precisemos “manipular o tempo” quando escrevendo testes para código cujo comportamento depende do momento no tempo.

Uma técnica comum é utilizar um mock ou stub na classe Time do Ruby para manipular o horário de acordo com o desejado. Isso vai contra um princípio importante do uso de fake objects em testes: “Não use fakes em objetos que não são seus“. Na maioria do tempo isso pode não causar problemas, mas alterar o comportamento de uma classe usada internamente pela linguagem não soa bem e pode causar bugs difíceis de rastrear.

Aí entra a gem time-warp. Ela ainda trabalha sobre as classes do Ruby, mas provê uma camada específica para testes para todo código executado em um bloco definido pelo programador. Um exemplo de uso (da nossa aplicação feita para o Rails Rumble):

it "should only silence tweets with the desired word inside the configured time interval" do
  pretend_now_is(Time.now.utc.beginning_of_day + 1.hour) do
    tweet1.sent_at = 2.minutes.ago
    tweet2.sent_at = 32.minutes.from_now
    tweet3.sent_at = 1.hour.from_now
 
    collection = [tweet1, tweet2, tweet3]
 
    Silencer.apply(collection, {:word => "soccer", :until => 30.minutes.from_now})
  end
 
  tweet1.should be_filtered
  tweet2.should be_filtered
  tweet3.should_not be_filtered
end

A gem adiciona o método “pretend_now_is”, que recebe um parâmetro com o horário desejado e um bloco. Dentro desse bloco, todo código executado é “transportado no tempo” para o horário definido. Além de tornar a manipulação das classes de tempo mais segura, o código fica muito mais elegante.

Veja mais detalhes no README da gem.


← Anterior Próxima →