terça-feira, 16 de dezembro de 2014

Improved how to render coffeescript partial inside coffeescript template

Some time ago I googled trying to find a solution for render a coffeescript partial inside a coffeescript template in an attempt to DRY my coffeescript templates.

This led me to https://coderwall.com/p/i62phq/how-to-render-coffeescript-partial-inside-coffeescript-template. Initially I turn my nose for the syntax, but it solved my problem and wasn't that terrible so I stick with this.

After some time I need to debug my JS response and when I looked at the returned code I saw that I need a better solution:

(function() {
  (function() {
    $('.footer').html("<div class=\'btn-group\'>...<\/div>");
  }).call(this);
;}).call(this); 

As you use more partials and your code start to grow this mess only gets worst. After hitting my head around a bit I realized that what I need was to render plain coffeescript, so I renamed my partial to _partial.coffee.erb and it worked like a charm!

Now my show.js.coffee is:

<%= render 'footer.coffee' %>

And my _footer.coffee.erb is:

$('.footer').html("<%= j render 'my_footer_html_partial' %>")

And the response is:

(function() {
  $('.footer').html("<div class=\'btn-group\'>...<\/div>");
}).call(this);  

Cleaner, don't you think?

segunda-feira, 8 de dezembro de 2014

Setup wildcard subdomain with Bind

I found a good documentation about configuring a DNS server to use wildcard domains for development: http://superrb.com/blog/2012/09/24/how-to-set-up-bind-on-ubuntu-for-a-wildcard-development-domain

All went well in my setup, I just have to adapt some paths and made use of bind conventions described in arch wiki.

All well, except the fundamental: wildcard subdomain. After googling a bit and read some similar questions in stackoverflow this was my final configuration:

  • /etc/named.conf
zone "dev.com" {
        type master;
        file "dev.com.zone";
};

  •  /var/named/dev.com.zone
;
; BIND data file for local loopback interface
;
$TTL 14400
@ IN  SOA dev.com. root.dev.com. (
            2014110801   ; Serial
                 86400   ; Refresh
                  7200   ; Retry
               3600000   ; Expire
                 86400 ) ; Negative Cache TTL
;
@ IN  NS  dev.com.
@ IN  A 127.0.0.1
* IN  CNAME dev.com.
@ IN  AAAA  ::1
If you don't catch the difference, I changed the line: "* IN A 127.0.0.1" with "* IN CNAME dev.com.".

PS.: This is NOT a tutorial, so read the post  linked in the start to make this works as you expect, since there contains what more you need to configure.

terça-feira, 3 de dezembro de 2013

Melhorando a performance dos seus testes com RSpec

Após começar a ficar entendiado e frustrado por ter de esperar quase 10 segundos para rodar um teste de integração, resolvi procurar alguma solução para o problema.

Já estava utilizando o servidor de DRb spork para ter o Rails já carregado na memória antes da execução dos testes, então resolvi pesquisar no google alguma solução para o meu problema.

Encontrei um ótimo post no ótimo blog The Carbon Emitter: http://blog.carbonfive.com/2011/02/02/crank-your-specs/ que leva a outro ótimo post em outro ótimo blog, o da 37signals: http://37signals.com/svn/posts/2742-the-road-to-faster-tests

Configurei o perftools.rb para rodar na minha máquina e como era de se esperar pelos posts acima, o garbage collector do estava sendo o vilão, segue a quantidade de chamadas na saída pprof.rb e o tempo, coletado com o comando time para executar apenas 1 teste:

      271  45.5%  45.5%      271  45.5% garbage_collector
      58   9.7%  55.3%       58   9.7% OpenSSL::PKCS5.pbkdf2_hmac_sha1
      20   3.4%  58.7%       21   3.5% Nokogiri::XML::XPathContext#evaluate
 
real 8.93
user 0.07
sys 0.00

Porém adotei uma abordagem um pouco diferente dos posts acima, alterei o arquivo spec/spec_helper.rb conforme o railscast #413 Fast Test (pro):

config.before(:each) { GC.disable }
config.after(:each) { GC.enable }

Com esta pequena mudança acabei conhecendo outro vilão, conforme mostra a saída a seguir, que é fruto da utilização do módulo confirmable do devise, porém já é possível perceber uma diminuição considerável no tempo do mesmo teste:

      58  16.9%  16.9%       58  16.9% OpenSSL::PKCS5.pbkdf2_hmac_sha1
      20   5.8%  22.7%       20   5.8% Nokogiri::XML::XPathContext#evaluate
      19   5.5%  28.2%       19   5.5% Regexp#===

real 6.57
user 0.07
sys 0.01

Não encontrei nenhuma forma de fazer com que o devise utilizasse uma função menos custosa, fui então dar uma olhada no código utilizado por eles e realizei o seguinte monkey patch através do arquivo spec/spec_helper.rb:

    class Devise::KeyGenerator
      def generate_key(salt, key_size=64)
        OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, 1, key_size)
      end
    end


Alterei o 3 argumento da função para 1, sendo que no código original este valor é de 65536 iterações realizadas pelo algoritmo para gerar a chave. Com esta alteração meu tempo sofreu novamente uma queda, porém desta vez sendo bem menos significativa:

      18   6.5%   6.5%       39  14.0% Psych::Parser#parse
      17   6.1%  12.5%       17   6.1% garbage_collector
      14   5.0%  17.6%       14   5.0% Regexp#===

real 6.27
user 0.08
sys 0.00

E pela saída apresentada pelo pprof.rb não existe mais o que atacar no código para melhorar a performance. Também é possível ter ganhos marginais utilizando o bloco within do capybara restringir os testes das páginas a regiões específicas do DOM. Ao se levar em conta milhares de testes é bom utilizá-lo como uma prática.

Passei então a imaginar o que poderia estar deixando meu código lento e imaginei que fosse a interação com o banco de dados, bingo! Configurei as seguintes opções do PostgreSQL para off, tornando-o praticamente um banco em memória (não faça isso em produção) e baixando o tempo para 3.74s:

fsync = off
synchronous_commit = off

real 3.74
user 0.09
sys 0.00

Uma melhora de quase 2,4x no tempo de execução de apenas 1 teste! Ao executar toda a suíte de teste, que ainda é bem pequena (possui apenas 35 testes) é que a diferença de velocidade se torna gritante: 26.5 x 8.85. E quanto mais testes eu tiver utilizando o banco de dados, pior para os exemplos sem as modificações no Postgres.

Neste meio tempo também troquei o spork pelo spring e adotei o guard-rspec. O spring faz a mesma tarefa para os testes que o spork faz, porém ele também otimiza a execução de outros comandos, como o rake routes, rake db:migrate, rails g, etc. Já o guard permite que meus testes rodem sem que eu tenha que sair do meu editor de texto e ainda me mostra uma bela notificação quando eles acabam de rodar!

Achei esta apresentação muito boa também, porém não vi nenhuma aplicação para os meus testes no estágio que eles estão atualmente, mas o speed up alcançado por eles é impressionante.

Estou muito mais feliz com o tempo do meu ciclo de BDD agora. E você, tem alguma dica para melhorar ainda mais esta performance?

terça-feira, 12 de fevereiro de 2013

Unicorn e Thin no Heroku

Depois de ver este post http://michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-with-the-new-celadon-cedar-stack/ decidi configurar uma aplicação no Heroku para utilizar o Unicorn ao invés do Thin.

Se você observar no post acima, existe um benchmark em relação ao tempo que levou os testes e a quantidade de requisições por segundo. Fiquei realmente animado com esta possibilidade para escalar aplicações, visto que cada dyno do heroku atende a uma requisição e a única possibilidade de antender mais requisições com o servidor Thin é aumentar o número de dynos.

O Unicorn foi desenvolvido para trabalhar com vários processos, fazendo fork de instâncias, deste modo em um único dyno é possível ter aproximadamente 3 processos, isso devido a limitação de memória oferecida por cada dyno que é de 512mb, porém se você adicionar mais um dyno você tem 6 processos rodando. Legal, não acha?

Com estas possibilidades animadoras resolvi fazer alguns testes para ver se utilizá-lo é realmente uma vantagem para deixar a resposta da aplicação mais rápida. Meu arquivo de configuração do Unicorn ficou exatamente como o deste post: http://stackoverflow.com/questions/9344788/am-i-preloading-the-app-in-heroku-unicorn-correctly

Para coletar os dados utilizei o comando httperf da seguinte maneira: httperf --hog --server meuservidor.com.br --ssl --ssl-no-reuse --num-conn=500 --ra=10 --timeout 30

Este comando irá fazer 500 conexões SSL com a página raiz do meu site (que não faz acesso a banco de dados), forçando handshake através da opção --ssl-no-reuse a uma taxa (--ra=10) de 10 conexões por segundo. Rodei o comando 3 vezes e fiz a média dos resultados obtidos para os seguintes valores de --ra: 10, 40, 80, 160, 320 e 500.

Então vamos aos dados obtidos:

Confesso que esperava mais do Unicorn, já que temos 3 processos atendendo requisições. A partir de 80 conexões ele estabeleceu em média 5 conexões a mais por segundo, sendo que em um dos testes o Thin conseguiu um desempenho um pouco melhor.
O tempo de resposta foi outra surpresa para mim, sendo que o Thin conseguiu ser mais rápido quando muitas conexões estão sendo estabelecidas por segundo.

Não vejo nenhuma vantagem clara de usar o Unicorn por enquanto, além de algumas vezes (raras) ter me deparado com o erro: httperf: failed to connect to SSL server (err=-1, reason=5).

Depois destes dados compilados, achei que fui muito suave e decidi ser mais agressivo em relação ao número de requisições. Requisitei 1500 conexões a uma taxa de 100 conexões por segundo (um site bem movimentado, não acha?). Nesta configuração ambos os servidores não conseguiram antender a todas as requisições (timeout), porém a performance de ambos os servidor foi semelhante, com o Unicorn atendendo um pouco mais de requisições (1233 x 1249), a taxa de conexão praticamente igual (20,8 x 21,6) assim como o tempo de resposta (3371ms x 3025ms).

Estes últimos testes atenderam mais de 1000 conexões concorrentes. Isso na versão para desenvolvedor do Heroku. Muito bom!

Ainda pretendo fazer testes em páginas que realizem consultas não triviais ao banco de dados para ver se os servidor apresentam tempos diferentes, mas isso fica para um próximo post...

sexta-feira, 21 de dezembro de 2012

BDD (Behaviour Driven Development): O que é?

O que!!! Eu nem aprendi TDD e já inventaram mais uma técnica de desenvolvimento de software? Calma, na verdade BDD é TDD sobre uma nova nomenclatura.

Se é a mesma coisa, então por que estão reinventando a roda? Faz parte do ser humano tentar melhorar suas ferramentas e conceitos. Com isso, você pode pensar que BDD é melhor, mas como já disse, as duas técnicas permitem atingir o mesmo fim, sendo assim o que vai influenciar sua percepção a respeito de cada uma é sua experiência com testes. Se você já utiliza TDD e se sente confortável, provavelmente não vai perceber grandes diferenças no BDD.

No meu caso, BDD caiu como uma luva. Comecei a aprender TDD e ficava me pergutando se os testes que estava escrevendo faziam sentido e nem sempre conseguia responder isto de forma prática. Analisando este passdo agora, percebo que essa dificuldade surgia da falta de experiência com a técnica, o que me fazia perder o foco do que era essencial: o software em desenvolvimento.

Após ler um pouco sobre BDD, comecei a entender que a técnica é exatamente TDD, porém a utilização de uma nova nomenclatura tornou as coisas muito claras para mim, pois a técnica força com que você pense desde o princípio no comportamento que você espera da sua aplicação, assim fica muito mais fácil pensar se seu teste está fazendo a coisa certa ou não.

BDD força você a pensar no que seu software vai fazer através de três construções bastantes simples:  Dado um determinado contexto; Quando algum evento acontece; Então eu espero uma determinada saída. Esta é a tríade do BDD: Given, When e Then.

Estas três palavras mágicas me ajudaram muito a programar com testes e estou extremamente satisfeito com meu ritmo de desenvolvimento. Nos próximos posts irei falar de algumas ferramentas que dão suporte para a técnica e os benefícios que percebo de sua aplicação.

Até a próxima!

terça-feira, 2 de outubro de 2012

Enviar convites com Rails acessando a lista de contatos do usuário

Esta é uma tarefa extremamente simples de ser feita. A parte mais difícil é juntar todas as peças e colocar pra funcionar de um jeito eficiente.

Através da gem omnicontacts é possível recuperar a lista de contatos do GMail, do Yahoo! e do Hotmail, ou seja, os três principais webmails utilizados hoje em dia.

Eu configurei para recuperar contatos apenas do GMail, porém requisitar um acesso a API dos outros serviços é a parte mais simples. Para adquirir o consumer_id e o client_secret exigido pela omnicontacts acesse o link "API Access" do site Google APIs.

No site da omnicontacts já existem as informações de como configurar o gem para rodar com a sua aplicação e obter contatos. Algo bastante simples de se fazer.

O que achei mais complicado foi fazer a visão pro usuário, pois no meu caso, tenho quase 800 contatos no GMail, o que imediatamente me faz pensar em utilizar paginação. Pensei em utilizar o gem will_paginate, porém para guardar os itens selecionados pelo usuário teria que utilizar AJAX ou fazer alguma programação do lado do cliente. Além disso, teria que manter a lista de contatos recuperada na sessão, o que não é nenhum grande problema, mas acaba sendo algo a mais para gerenciar.

Foi então que me lembrei do DataTables, um ótimo componente em JQuery para criar paginação, ordenamento e pesquisa a partir de uma tabela. E o pessoal da comunidade Rails já criou até algumas coisas para facilitar seu uso e que estão muito bem explicados no RailsCasts #340!

Em um primeiro momento fiquei preocupado com a quantidade de dados que seria transferida para minha aplicação, mas os meus quase 800 contatos ficaram em aproximidadmente 45kb, ou seja, nada de assustar para os padrões de rede atuais.

A parte mais complicada desta solução é provavelmente o envio das informações para o servidor, que é feita através deste código (app/assets/javascript/contato.js.coffee):

$(document).ready ->
  $('form').submit ->
    elementos = $('input', oTable.fnGetNodes()).serializeArray()
    $(elementos).each (index, elemento) ->
      input = $("").attr("type", "hidden").attr("name", "emails[]").val(elemento.value)
      $('form').append($(input))  

Este código pega todos os itens marcados pelo usuário (linha 3) e para cada um deles cria um campo de input escondido com o e-mail e o adiciona ao formulário (linhas 5 e 6).

Criei uma aplicação para testar estas coisas, a única coisa que precisa ser alterada nela é o arquivo config/initializers/omnicontacts.rb para conter seu consumer_id e seu client_secret. Baixe aqui!

Happy hacking!

quinta-feira, 6 de setembro de 2012

Nested resources com mesmo nome e visões diferentes

Estou desenvolvendo uma aplicação em Rails e cheguei em um momente que tinha o seguinte problema: renderizar conteúdo diferente para 1 recurso aninhado de outros 2.

Vou utilizar um exemplo real para ilustrar melhor o caso. Digamos que estamos trabalhando numa aplicação parecida com o twitter e nossos 3 modelos são: usuários, postagens e tags. A partir delas eu posso ter as seguintes URLs na minha aplicação:
  • /usuario/1/postagens
  • /tags/1/postagens
Sendo necessário a seguinte configuração no meu arquivo routes.rb para obtê-las:

resources :usuarios do
  resources :postagens
end

resources :tags do
  resources :postagens
end

Sem nenhuma configuração adicional, isso irá fazer com que ambas as URL direcionem suas requisições para o mesmo controlador: PostagensController.

Para modificar este comportamento podemos utilizar namespaces. Para isso podemos criar uma pasta chamada usuario e outra chamada tag dentro do caminho /app/controllers e dentro dela colocar a classe PostagensController com o namespace correto, isto é o topo do arquivo teria que ficar da seguinte forma:
  • class Usuario::PostagensControllers < ApplicationController
  • class Tag::PostagensControllers < ApplicationController
Desta forma separamos o controlador de cada um dos nosso recursos aninhados, mas ainda precisamos instruir o Rails que ao receber uma requisição em um dos dois caminhos anteriores queremos que esta seja redirecionada para um controlador ou outro. Os guias na página do Rails tem uma parte ótima a este respeito: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing

Para o meu caso modifiquei o arquivo routes.rb para o seguinte:

resources :usuarios do
  resources :postagens, :module => "usuario"
end

resources :tags do
  resources :postagens, :module => "tag"
end


Desta forma a URL não é alterada, apenas é feito o roteamento para o controlador no namespace correto.

O maior benefício desta estratégia é poder separar as visões para cada uma das requisições, sendo que o que é geral para as duas pode ser extraída para um template, enquanto os recursos específicos não ficam poluídos com ifs desnecessários e que tornam o entendimento da aplicação mais difícil, pois acaba adicionando detalhes de domínios distintos, podendo levar a distrações durante a leitura do código.

Os arquivos da visão ficariam então no seguinte caminho:
  • app/views/usuario/postagens/index.html.erb
  • app/views/tags/postagens/index.html.erb
A seção "Grouping Controllers into Modules" do livro Agile Web Development with Rails foi de grande ajuda para descobrir como implementar esta abordagem.
Maravilha, não!?!