wicz journal

Everybody's worried about time, but I just keep that shit off my mind. 

Testing subdomains and redirects with Cucumber

The other day I was writing some Cucumber features for a Rails app that relies on subdomains for creating per-user contexts. It seems that Webrat can't handle subdomains and redirects the way I expected.

A Little Background

I hate when I have to access 127.0.0.1 or localhost:3000. Typing all these numbers, dots and colon doesn't feel comfortable at all. I like domain names, and since I am developing a subdomain-aware app, I want to be able to access using names. That said, I configured my Firefox with a PAC file that routes *.local to my server running at 127.0.0.1:3000 (oh man, if you're still using /etc/hosts you're so 2000-and-late! =p).

Here's how it looks like. You can grab more details here.

function FindProxyForURL(url, host) {
    if (shExpMatch(host, "*.local")) {
        return "PROXY 127.0.0.1:3000";
    }
    return "DIRECT";
}


Now I am able to access johndoe.app.local, foobar.app.local, etc. No numbers, no colon, just NAMES! =)

My ApplicationController implements a simple before_filter that checks for a valid account, otherwise redirects to a fallback page. Something like this:

before_filter :account_required

def current_account
  @current_account ||= Account.find_by_subdomain(request.subdomains.first)
end

def account_required
  unless current_account
    flash[:error] = :account_not_found
    redirect_to fallback_url
  end
end


You can have more on subdomains as accounts here, here and here.

The Scenario

The feature was a simple sign in.

Given the foobar account
When I go to foobar's sign in page 
And I fill in "user_session[email]" with "foobar@test.com"
And I fill in "user_session[password]" with "1234"
And I press "Sign in"
Then I should be on dashboard
And I should see "Welcome, foobar"


The Caveats

By default, Webrat uses www.example.com as host for testing. Since it was trying to sign in to a account that doesn't exist (the Given creates foobar), it was being redirect to the fallback url, so it couldn't find the form fields. Knowing that Webrat's RailsAdapter uses ActionController::Integration::Session, we can easily solve this by overwriting the host name to use in the next request. Our Given should look like this:

Given /^the foobar account$/ do
  Foobar.create(...)
  host! "foobar.app.local"
end


Now being able to fill in the form, after submitting it, I still wasn't sent to the expected page. I was willing to see the dashboard, but it was rendering /session, which means I wasn't authenticating at all, even passing valid credentials... WTF!? Then dumping the ActionController::Response object, I verified that it was actually redirecting (@status => "302 Found"), so I decided to investigate Webrat.

Webrat's behavior is to follow any redirects, except for external ones. And subdomains aren't considered as externals. Digging a little deeper, people have reported similar problems and patches (although I've tried none) here, here, here and here. Since the problem seems that Webrat shows some really deep love to example.com, I came up with a ugly-and-fast-but-it-works solution:

Set a domain in my environment.rb:

APP_DOMAIN = "app." + case RAILS_ENV
when "production" then "com"
when "cucumber" then "example.com"
else "local"
end

And changed the above Given step to host! "foobar.#{APP_DOMAIN}".

Bar green, code clean, life moves on.

Loading mentions Retweet
Filed under  //   bdd   cucumber   rails  

Comments [0]

User-friendly location-aware web apps

Who have never ever filled a form like this please stand up.

Anyone? Anyone?

Well, you'll have to agree with me that filling forms like this is a PITA! But I understand that may be necessary in certain cases. Maybe in apps that people really need this granularity, this is an easy way to get each field of an address separately.

But if it's not your case and like me you can sacrifice the formalism in order to user experience, I present you geo-autocomplete. It's a nice jQuery plugin to autocomplete location using Google Maps v3 API and Google Static Maps v2 API.

Now you are able to change that gigantic form to a simple textarea, and still have a nicely formatted address. And since the plugin queries the Google Maps v3 API Geocoder, you also get latitude and longitude values. It's fast and smooth, definitely worthwhile to give it a try.

Loading mentions Retweet
Filed under  //   google   maps   ux  

Comments [0]

Posterous to the rescue

Posterous to the lazy^H^H^H^H rescue.

If you are as lazy as I am (to keep your own Wordpress installation), you should definitely try posterous.

It has some neat features like posting from email (this post), it knows how to handle images, videos and audio, autoposting to others networks like Twitter, Facebook, etc. You can even configure a custom domain, just like mine. It's a great opportunity to remove the the dust from your old blog of yours and get back to business. BTW, update your feeds!

Loading mentions Retweet
Filed under  //   posterous  

Comments [0]

Escrevendo boas user stories / estórias

Como bem sabemos, um dos princípios dos processos Ágeis é satisfazer o cliente, agregando valor ao produto final. De certa forma, para que essa tarefa possa ser realizada com sucesso, é preciso saber exatamente as necessidades desse cliente.

Felizmente com algumas estórias e feedbacks já é possível ter uma boa idéia de onde devemos chegar. Mas é importante ressaltar que a “qualidade” das estórias influencia diretamente em todo o processo.

As estórias apresentam três aspectos críticos, os quais devem ser obrigatoriamente lembrados no momento de sua criação. São eles: Cards, Conversation, Confirmation. Ou 3C.

Cards — Estórias são escritas em cartões ou post-its. Na verdade o que importa aqui é o tamanho! A sugestão dos cartões e post-its é pelo fato de serem pequenos. E cartões pequenos naturalmente forçam estórias pequenas, de duas a três linhas no máximo.

Conversation — A estória escrita no cartão serve como um lembrete, uma maneira de identificar uma funcionalidade que foi conversada e discutida entre os clientes e desenvolvedores.

Confirmation — Depois das funcionalidades terem sido discutidas e escritas nos cartões, o cliente define (implícita ou explicitamente) uma maneira de validar esse pedido. Geralmente essa confirmação é feita com testes de aceitação.

Para criar boas estórias, ainda devemos focar em seis atributos: INVEST

Independent — Estórias devem ser independentes uma das outras. Dependências entre estórias geram problemas de planejamento e priorização, sem falar que dificultam bastante nas estimativas.

Negotiable — Estórias não são contratos. Como dito anteriomente, estórias são lembretes para funcionalidades discutidas (negociadas) entre o cliente e os desenvolvedores.

Valuable — Na mesma linha dos processos Ágeis, como dito no início deste post. Estórias devem agregar valor para o cliente.

Estimatable — Os desenvolvedores devem ser capazes de estimar o tamanhos das estórias. Geralmente estórias incompletas ou muito grandes (complexas) são difíceis de serem estimadas. Portanto invista em discussões e quebre em estórias menores quando necessário.

Small — “Tamanho é documento”. Essa regra é valida para a criação de boas estórias. Como dito anteriormente, estórias grandes dificultam as estimativas. Bem como estórias muito pequenas. Quebre ou agrupe dependendo do caso.

Testable — Estórias devem ser possíveis de serem testadas. Um teste que é executado com sucesso, prova que a estória foi desenvolvida com sucesso, atingindo as necessidades do cliente. Estórias que não podem ser testadas geralmente especificam requisitos não-funcionais do software, e não uma funcionalidade diretamente.

Além do 3C e INVEST, vejamos mais alguns pontos. Foque as estórias no “O que” e não no “Porque”. Estórias não devem apresentar termos técnicos e nem os mínimos detalhes das funcionalidades. Lembre-se, elas são apenas lembretes do que foi discutido anteriomente.

Quando possível aplique o “Quem”, “O que” e “Como”. Por exemplo: “O visitante pode se cadastrar no portal pelo formulário”, “O visitante confirma seu cadastro por email”, “O usuário é capaz de salvar seus favoritos”. Mas cuidado com o detalhismo!

Use e abuse de metáforas. Você vai perceber como fica fácil de explicar (ou entender) suas idéias quando você consegue comparar com algo concreto, do dia-a-dia das pessoas. Sem falar que assim você consegue definir um vocabulário comum com o cliente.

Incentive o cliente a escrever as estórias. Assim você acaba forçando-o a explicar com clareza as suas necessidades e muitas vezes ajuda também a esclarecer possíveis dúvidas.

Para finalizar, abaixo um trecho retirado de [1], que explica quase tudo em um único parágrafo:

The story is the unit of functionality in an XP project. We demonstate progress by delivering tested, integrated code that implements a story. A story should be understandable to customers and developers, testable, valuable to the customer, and small enough so that the programmers can build half a dozen in an iteration.

Referências/Leitura recomendada:

[1] Planning Extreme Programming. Kent Beck, Martin Fowler
[2] Essential XP: Card, Conversation, Confirmation. Ron Jeffries
[3] User Stories Applied: For Agile Software Development. Mike Cohn

Loading mentions Retweet
Filed under  //   agile   user-stories  

Comments [0]

Dicas valiosas para sprints

Olá. Bem, é como dizem por ai: “Life got real!”. Mas, enfim, estou aqui de volta.

Ainda tratando de sprints. Seguindo na mesma linha do post anterior. Acho que ficou claro que não é sensato abraçar cegamente o que é sugerido pela literatura, e sim saber reconhecer a essência do que é proposto e conseguir adaptar e aplicar à sua realidade. E além do mais, saber aplicar tais conceitos a cada caso é o tipo de tarefa que só se consegue realizar com a prática do dia-a-dia. E foi justamente com a prática do dia-a-dia que eu percebi alguns detalhes nos meus projetos. Seguinte:

  • Fixe os dias da semana para marcar suas reuniões de planejamento e retrospectiva (sprint planning e review). Por exemplo, todos os plannings acontecem na segunda-feira e todos os reviews na sexta-feira. Dessa forma você acaba criando um vínculo e fica mais fácil de todos se organizarem e dificilmente alguém vai esquecer da reunião;
  • Certifique-se que os dias dos sprints planning e reviews estão “funcionando” pra você. O que eu quero dizer com funcionando, é se estão sendo reuniões produtivas. Nos meus primeiros projetos eu reservava a segunda-feira para o planejamento e a sexta-feira (da outra semana) para as retrospectivas. Tiro no pé! Ninguém, nem a equipe, nem o Product Owner estavam motivados para começar a semana com uma reunião. Estas sempre começavam atrasadas e era nítido que o pessoal ainda estava “regulando a marcha lenta”. Muito menos encarar uma retrospectiva de 4 horas em plena sexta-feira! Bastou trocar os dias e a coisa começou a funcionar;
  • Lançar novas versões do produto na sexta-feira pode não ser uma boa idéia. Ninguém quer voltar para casa, muito menos correr o risco de perder o final de semana com aquela preocupação de que algo pode dar errado. Uma coisa que funcionou comigo foi definir um deadline na quinta-feira. E deixar a sexta-feira apenas para algumas tarefas administrativas e reviews;
  • Crie tags no seu sistema de controle versão para cada sprint. Isso se você estiver utilizando controle de versão, pois se não estiver, você definitivamente deveria!
  • Evite entregar tudo o que foi produzido apenas ao final da iteração. A medida que as tarefas forem sendo finalizadas, disponibilize para o cliente. Agilidade está diretamente relacionada a feedback. Se você deixar para entregar tudo que foi feito ao final do sprint, você só tera o feedback do cliente no próximo sprint, o que pode acabar atrasando as coisas, haja vista já existem tarefas definidas para esse (próximo) sprint. Esse assunto também foi abordado neste excelente artigo do Alisson Vale, inclusive batizado com um nome bastente adequado: “Síndrome da Iteração Inacabada”.

Bem, por hora é isso. Como cada empresa ou projeto, cada situação tem suas peculiaridades, eu gostaria que vocês compartilhassem suas experiências com relação a esse assunto. Os comentário estão abertos. Caso você não tenha passado por isso ainda, espero que esses tópicos possam te poupar algum tempo.

Sem mais.

Loading mentions Retweet
Filed under  //   agile  

Comments [0]

Tamanho ideal de sprint/iteração (Scrum/XP)

Antes que comecem as críticas, quero deixar claro que o título escolhido foi proposital. Não por provocação, pelo contrário, mas para tentar abrir os olhos de quem ainda acredita que seguir à risca a bibliografia é sempre a melhor solução. E acaba ferindo (mesmo que cegamente) um dos princípios mais importantes da Agilidade: Adaptação.

Não me recordo o número, mas posso afirmar que não foram poucas as vezes que ouvi ou li alguém questionando sobre o tamanho dos sprints ou iterações. Se eram obrigados a trabalhar com 30 dias, ou se optando por um valor diferente estariam certos ou errados.

Para quem esperava uma solução simples e objetiva, sinto muito. A verdade é que não existe bala de prata, nem certo ou errado. Não existe um tamanho ideal que se aplique a todas as ocasiões. Cada caso é um caso. Mesmo em uma equipe que não sofre alterações de pessoal, um tamanho adequado para um projeto, pode não ter a mesma eficiência em outro.

O Scrum sugere sprints com 30 dias (um mês) de duração (“Do I need to stick to a month time frame?” em Scrum FAQ, ou na versão traduzida). O XP sugere ciclos semanais. Durante meu treinamento Certified ScrumMaster foi proposto sprints de 28 dias, pois facilita visualização em termos de semanas. Além desses, eu já tive oportunidade de trabalhar com sprints de 1 e 2 semanas. O que eu sugiro pra você: Experimente! Só assim você vai ser capaz de dizer o que é apropriado para cada ocasião. No mais, eu só posso citar alguns pontos que devem ser levados em consideração para a sua decisão:

  • Escolha uma duração a qual seja agradável trabalhar, tal que a equipe consiga manter um ritmo sustentável. Sprints muito longos podem levar à procrastinação (Síndrome do Estudante). Já sprints muito curtos conseguem ser bem estressantes quando algum imprevisto acontece;
  • Requisitos mudam com freqüência (i.e., o cliente muda os planos constantemente ou é incapaz de especificar com clareza o que deseja). Se for pra algo dar errado, que seja agora e não daqui 15 dias. Ou seja, quanto antes você perceber que esta no caminho errado, o esforço para voltar atrás é menor. E você só conhece esse caminho a partir do feedback, o que (geralmente) acontece mais frequentemente em sprints curtos;
  • Semelhante as incertezas do cliente, deve-se ponderar as incertezas da equipe. Pois esta pode ser incapaz de dizer o quanto consegue trabalhar por iteração ou desconhece de aspectos técnicos do projeto;
  • Da mesma forma que os requisitos podem mudar, o mesmo pode acontecer com suas prioridades. O seu tempo de resposta para eventuais mudanças esta intimamente ligado à duração dos sprints;
  • Preparação (overhead) para os sprints. Suponha que antes de cada sprint todo o sistema precise passar por uma bateria de testes, ou que todo desenvolvedor deva reinstalar seu sistema e ambiente de desenvolvimento por medidas de segurança da empresa. Sem dúvida sprints curtos não são a melhor escolha nesse caso. O ideal seria reduzir ou eliminar estes impedimentos, mas nem sempre isso é possível.

Bem, se você tinha dúvidas com relação o tamanho dos seus sprints, espero esses tópicos sirvam como ponto de partida para uma possível mudança. Mas não esqueça que até mesmo as mudanças visando melhorias têm seus efeitos colaterais. Portanto, uma vez definida uma duração apropriada para seus sprints, respeite esse valor, pois só assim você será capaz de manter um ritmo (velocidade) de trabalho.

Inspect and Adapt!

Loading mentions Retweet
Filed under  //   agile  

Comments [0]

TDD em: O que testar?

Quando comecei a implantar desenvolvimento guiado por testes (TDD) na empresa em que trabalhava, tive a sorte de fazer parte de uma equipe de desenvolvedores bastante competente. Com apenas uma apresentação de poucos minutos e duas semanas de prática, quase todos já conseguiram captar que a essência do TDD não é apenas validação de código, mas também a especificação de determinada funcionalidade.

Tive apenas um caso em especial. Depois de algumas sessões de programação em par passei o teclado para o companheiro. Ele virou pra mim e disse: “Tá, e agora?”. Nós já tínhamos discutidos anteriomente o contexto da funcionalidade, mas mesmo assim ele estava repleto de dúvidas sobre o que realmente implementar

Para tentar esclarecer um pouco as dúvidas, fiz uma breve pesquisa na bibliografia e cheguei nos conceitos Right-BICEP e CORRECT.

  • Right – Are the results right?
Dados valores de entrada e seus respectivos valores de saída, verifica-se se a implementação esta de acordo, ou seja, se os resultados estão certos.
  • B – Are all the boundary conditions CORRECT?
Verificar se os valores estão dentro do domínio, dos limites aceitáveis. Por exemplo, uma validação de preenchimento de um campo, ou ainda se este foi preenchido na formatação adequada. Veja abaixo a descrição do acrônimo CORRECT, que descreve algumas condições de limites.
  • I – Can you check inverse relationships?
Alguns métodos podem ser verificados aplicando a sua lógica inversa. Por exemplo, para verificar o resultado de uma divisão, podemos comparar o dividendo com a multiplicação do divisor com o quociente, adicionado ao resto.
  • C – Can you cross-check results usings other means?
Semelhante a relação inversa, podemos verificar os resultados por outros meios. Podemos certificar o sucesso de uma inserção de uma elemento em um vetor, verificando se o tamanho deste antes da inserção e acrescido de um, é igual o tamanho depois da inserção (1 + Ni = Ni+1).
  • E – Can you force error conditions to happen?
Verificar como a aplicação se comporta em situações adversas. Podemos forçar um erro simples, com uma passagem de parâmetros incorreta, por exemplo. Mas não podemos esquecer dos outros diversos possíveis problemas do dia-a-dia. Uma falha na comunicação, espaço em disco que se acaba, memória insuficiente, etc. Uma maneira de testar isso é a utilização de objetos Mock?. Mas isso já é pano para outra manga =)
  • P – Are performance characteristics within bounds?
Nesse caso não queremos testar o desempenho em si, mas sim se a curva de desempenho se mantém estável, mesmo variando os cenários. Suponha que os testes de uma busca em um vetor de tamanho N passam em tempo t. E se agora o vetor for de tamanho N+M, os testes continuam passando em tempo t+m?

Como muitos dos problemas aparecem na verificação das entradas e saídas, é importante ter bem definido o seu domínio, ou limites (boundary). Felizmente temos mais uma ferramenta para nos ajudar nessa definição.

  • Conformance – Does the value conform to an expected format?
Verifica se o valor em questão esta de acordo com o formato estabelecido. Por exemplo, um CPF ou CNPJ, ou ainda uma estrutura mais complexa como uma árvore binária.
  • Ordering – Is the set of values ordered or unordered as appropriate?
Diz respeito a ordenação dos valores. Suponha os processos de uma cafeteira (bom exemplo!): colocarFiltro(), colocarPo(), colocarAgua(), servirCafe(). Esses processos necessariamente precisam estar nessa ordem, caso contrário ninguém vai conseguir beber o valor de saída.
  • Range – Is the value within reasonable minimum and maximum values?
Dado valor deve estar dentro do domínio. Por exemplo, o preenchimento do ano de nascimento em um formulário [1900,2007].
  • Reference – Does the code reference anything external that isn’t under direct control of the code itself?
Verificar se um cenário referencia ou depende de outro fora do seu escopo. Suponha um portal de compras. Antes de adicionar qualquer produto ao carrinho, o usuário deve ter iniciado uma sessão (efetuado login). Existem pré e pós-condições que devem ser satisfeitas para passar o teste.
  • Existence – Does the value exist (e.g., is non-null, nonzero, present in a set, etc.)?
O teste mais intuitivo, acho. Verificar e um determinado valor de fato existe. Se certo parâmetro foi preenchido.
  • Cardinality – Are there exactly enough values?
Outro simples também. Se a cardinalidade, quantidade dos parâmetros passados é suficiente.
  • Time (absolute and relative) – Is everything happening in order? At the right time? In time?
Devemos verificar se execução de diversos processos em ordem. Cada um executando no momento certo. Lembra do exemplo da cafeteira? Também se aplica aqui. Eu disse que era um bom exemplo =). Você também pode imaginar uma linha de produção.

Acho que isso é um bom começo. Mas gostaria de deixar bem claro que isso não se trata de um guia, muito menos de uma receita de bolo. São apenas alguns lembretes para facilitar e aprimorar a implementação dos seus testes. Caso você tenha se interessado neste tópico e queira a versão in extenso, você DEVE ler Pragmatic Unit Testing in Java with JUnit.

Feliz TDD!

Loading mentions Retweet
Filed under  //   tdd  

Comments [0]