Arquivos para 'desenvolvimento'Categoria

Um produto por semana

30 de março de 2010

Para atender a demanda de um cliente decidimos aplicar uma técnica de criação rápida de um produto. Ele precisava de uma ferramenta de otimização de feeds e widgets, permitindo encontrar novos parceiros – indo um passo a mais de distância que o Urchin ou Analytics.

Duas semanas depois, o Probe estava no ar atendendo as requisições internas e gerando estatísticas importantes sobre parceiros de qualquer empresa. Mas o que permitiu entregar um produto tão rápido?

Fugindo do brainstorm

A idéia do produto já havia sido discutida internamente na Caelum entre diversas pessoas, o que amadurece a mesma, permitindo cortar idéias não triviais que seriam danosas a uma primeira entrega. Esse período não foi um brainstorm onde determinadas pessoas sentam numa mesa e discutem ao máximo determinado assunto, tentando chegar na visão ótima do que seria seu produto. Pelo contrário, isso não seria nada ágil.

Não existe e consequentemente é impossível alcançar algo perfeito, adaptamos o que temos para chegar o mais próximo do idealizado.

Discutir no dia a dia a idéia com diversas mentes que entendem um pouco ou muito do assunto amadurece aos poucos a visão que temos do produto.

A interface

Por mais que alguns projetos com os quais os usuários interagem possam ser tocados sem wireframe, para evitar dúvidas pontuais de CSS, usabilidade etc, utilizamos um design pronto (simples, intuitivo e direto), economizando tempo de pesquisa e encaixe pois as lógicas já eram criadas no design final.

Fazer o mínimo possível

Com o design em mãos e uma visão razoável do que queremos, escolhemos as funcionalidades mínimas para ter um produto que entregue algo que os produtos similares (Feedburner, Analytics etc) ainda não fazem. Essas funcionalidades, um subconjunto de histórias, foi definido como o objetivo ideal de entrega: o que deixaria o produto um passo a frente dos concorrentes.

Além disso, o PO possuia uma data de entrega, quando o sistema deveria estar no ar, que só ele conhecia. E aí entra a questão: se a data e o escopo estão fixos, perderemos qualidade.

Excluindo funcionalidades

Para fugir da perda de qualidade, o escopo era ideal, mas não fixo. Se fosse possível entregar tudo o que o PO desejava, ótimo, se não, ele deve estar pronto para lidar com o que foi entregue. Durante essa fase, o PO é capaz de rejulgar o escopo.

Após poucos dias, algumas funcionalidades foram cortadas, pois ficou claro que a ferramenta já entregaria valor suficiente com menos do que originalmente pensado para o primeiro release.

Excluindo funcionalidades

Mais alguns dias e novamente outras funcionalidades se apresentaram desnecessárias, junto com a maior importância na data de entrega do que no escopo a ser entregue. Com isso, menos funcionalidades (menos valor) seriam feitas, mas teríamos um produto que retorna valor em breve.

Priorizando o backlog

Priorizar o backlog adequadamente foi outra ação fundamental para entregar o máximo de valor possível no produto desenvolvido.

Excluindo funcionalidades

A equipe não possui um comprometimento com um escopo em uma data específica, portanto é responsabilidade do PO escolher o que é melhor ser entregue nesse período, isto é, priorizar corretamente.

Foram mais de duas vezes durante o período de desenvolvimento que cortamos funcionalidades. Em todas elas ganhamos tempo pois entregaríamos algo usável antes do planejado.

Equipe mínima

Em um início de produto tão rápido, é necessário manter uma equipe pequena pois qualquer burocratização do dia a dia de desenvolvimento levaria tempo demasiado para encaixar-se nas poucas horas. No nosso caso, existiam dois desenvolvedores e sentimos que em um grupo de até três, talvez quatro, seria possível fazer um trabalho similar.

Qualidade

Apesar de usar as práticas mais educadas possíveis, houve uma queda na qualidade, algo que o PO teve que pesar: após as 64 horas de desenvolvimento (2 pessoas, 4 dias úteis), tivemos mais 60 horas para investir somente em testes e refatorações.

A partir daqui, o desenvolvimento deve ser feito seguindo todas as práticas que acreditamos, sem margem para entregas rápidas como essa primeira pois a complexidade desse trabalho aumenta muito.

Pareamento e isolamento

A equipe se manteve razoavelmente distante de outras equipes de desenvolvimento e combinou pareamento com programação não pareada. Houve um equilíbrio de forças, misturando a propriedade coletiva do código com a produtividade que foi necessária. Novamente, após essa primeira entrega, abrir mão do pareamento se torna inviável.

Cliente ao lado

A qualquer instante os desenvolvedores tinham acesso ao PO e o cliente, tomando alguns cuidados. Esse é um ponto a ser defendido a todo custo se a entrega de uma versão inicial seguirá esse padrão. A qualquer instante o cliente poderá remover histórias desnecessárias ou solucionar problemas.

Na continuidade do projeto, isso já se torna diferente, uma vez que não esperamos re-priorizações dentro de sprint ou um cliente 100% liberado para os desenvolvedores.

Outros

Existem daily meetings, feedback rápido etc, como as práticas ágeis defendem.

A entrega

Após ter entrado em produção notamos que o tempo todo de desenvolvimento, o foco estava voltando na entrega de algo utilizável, algo com valor para o cliente, que no dia seguinte já poderia colocar em produção.

Deixamos um front end aberto da aplicação para quem desejar visualizá-lo, apesar do back end envolver funcionalidades ligadas com REST, feeds, widgets etc que não estão visíveis no mesmo.

Resumindo

O primeiro release de um produto pode ser feito com práticas ágeis que fujam um pouco da qualidade máxima que tentamos atingir, viabilizando uma entrega rápida – mas não necessariamente ágil a todo instante – e valiosa.

Mas nada disso serve como desculpa para manter o desenvolvimento do produto dessa maneira posteriormente: a preocupação com a qualidade deve voltar ao máximo e a partir desse instante um método de desenvolvimento mais formal (como Scrum, Lean etc) deve ser seguido.

Post criado junto com o Thiago Ferreira da Caelum.

Filtros REST em Rails e Java

18 de março de 2010

Para aqueles que gostariam de ver somente o conteúdo relativo as notícias de gerenciamento ágil, assinem o feed da categoria agile.

Para quem gostaria de assinar o feed completo, utilize o feed principal.

Muitas aplicações web possuem páginas de relatórios com campos para filtragem. O exemplo mais famoso é o caso onde o usuário pode configurar a data inicial e final para filtragem de dados.

FIltragem de dados

Mas o que acontece quando o usuário clica em qualquer link desse relatório, ou de relatórios consecutivos que aparecem após o mesmo? A data se perde. Em situações genéricas, o filtro se perde.

Vou exemplificar três maneiras de implementar tal funcionalidade.

Armazenar na sessão

É muito comum ver aplicações onde na primeira tela somos responsáveis por escolher, por exemplo, com qual unidade, centro de custo ou contrato desejamos trabalhar e, a partir de então, com tal valor armazenado na sessão no lado do servidor, temos acesso a URIs como http://www.projeto.com.br/clientes que retornaria a lista de clientes de uma unidade.

O que acontece se desejo trabalhar com clientes de duas unidades ao mesmo tempo, em abas distintas? Tenho que mudar de unidade a cada clique que executo com clientes de unidades diferentes.

Além disso, caches públicos como proxies entre o servidor e o cliente não terão o mesmo ganho de desempenho com URIs identificadoras de recursos reais.

O load-balancing também se torna custoso pois a sessão fica presa a uma máquina ou deve ser replicada em determinados momentos.

Tudo isso acontece pois sua aplicação é stateful, quebrando uma das regras da arquitetura REST.

O escopo flash é uma solução que cai nessa categoria.

Parâmetros do request

Outra solução é quando as características do filtro são passadas por parâmetros em uma URI do acessada através de GET.

parametros get

Nesse caso, podemos sobrescrever o método utilizado para definição de links para sempre adicionar os parâmetros de filtagem (url-rewriting):


  # remembers the starting and end date on all links
  def url_for(options = {})
    options[:start_date] = params[:start_date]
    options[:end_date] = params[:end_date]
    super(options)
  end

  public String urlFor(Class resource, String method) {
     return "/" + resource.getName() + "&start_date=" + params("start_date") + ...;
  }

Note que em ambos os casos é possível criar um componente que decide se o parâmetro de filtragem deve ou não ser adicionado.

Com um único método (monkey patch no Rails ou definição de tag no Java) somos capazes de resolver o problema em todos os links de um sistema.

Note que com essa abordagem, não existem os problemas de sessão apresentados anteriormente.

Armazenar um cookie no client

Aqui, como na solução baseada em sessões, existe o problema do trabalho em unidades distintas em diversas abas.

Uma vez que o cookie registrou informações relativas ao estado do cliente no processo definido no servidor, as próximas requisições irão levar em consideração tal informação, em todas as abas.

Novamente perdemos escalabilidade e, se usado em conjunto com sessões, temos um fator a mais negativo no load balancing.

REST

A segunda solução é a única que se aproxima mais de uma arquitetura REST: o servidor não mantém estado e a URI identifica um recurso, onde, por exemplo, open search pode ser utilizado para o sistema de filtragem.

O segredo está em deixar o cliente através de recursos identificados por URIs, ser guiado pelo servidor, e nenhum dos dois armazenem informações relativas ao estado atual de um processo. Os recursos e seus links ditam o processo (HATEOAS).

Note que de todas as soluções, ela foi a mais simples de trabalhar e com mais vantagens.

Além disso, não foram usados cookies que quebram a transparência para layers intermediários.

Fuja de cookies e de sessões, viva uma vida mais rest.

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.