Archive for the ‘Refactoring’ Category

Agile UX: Como trabalhar com os designers

Friday, December 19th, 2008

Seguindo com a série de posts-resposta, vou aproveitar mais um e-mail que recebi para falar de um assunto que é campeão em dúvidas e discussões: como trabalhar com os designers. A questão é a seguinte:

Gostaria de tirar uma dúvida (ou mesmo sugestão) sobre como vcs estão trabalhando ai na Globo.com com os designers, arquitetos de informação, etc, inseridos nos times ágeis.

A empresa onde trabalho tem um “setor” de criação artística muito forte, alias, excelentes profissionais, e eles trabalham independentes praticamente do desenvolvimento.

Devido a maneira da empresa gerir seus projetos – waterfall – eles fazem toda a parte de criação e entregam um wireframe+layout de telas prontos pras equipes de desenvolvimento, ai é cada um por si.

Como estamos fazendo um processo de migração de waterfall pra desenvolvimento ágil, esse ponto específico do pessoal de criação inseridos nas equipes ágeis ainda deixa muitas dúvidas, na maneira que eles podem fazer parte dos times.

Talvez esse tenha sido um dos maiores problemas que tivemos na adoção de Scrum aqui na Globo.com, ou pelo menos é um dos problemas que têm durado mais tempo. Novamente, não acho que exista uma receita de bolo, cada time ou empresa precisa encontrar a melhor forma de trabalhar. Vou me limitar a dar algumas idéias e falar do que temos tentado fazer aqui para integrar desenvolvimento e design.

Por último, vou falar especificamente de Scrum porque é o que usamos aqui (apesar de usarmos também práticas e conceitos de XP e Lean), mas as mesmas idéias servem para outros processos similares.

O ponto de vista do processo

Do ponto de vista do Scrum, o correto seria desenhar a cada história que fosse feita somente as partes da tela necessárias para a conclusão da história.

Fazer todo o design antes nos mínimos detalhes não é o mais indicado porque para isso é preciso fazer um levantamento de requisitos para entender as necessidades e é exatamente assim que funciona a fase de análise e levantamento de requisitos do waterfall (ou seja, o que não queremos fazer).

Outro problema é que se no início de um projeto você só trabalha telas, o que você irá entregar no fim de um Sprint? Com certeza não será software funcionando e toda aquela história de antecipação do ROI vai por água a baixo.

Por fim, um dos objetivos do desenvolvimento com Scrum é produzir software de maneira iterativa e incremental. A cada Sprint deveria ser entregue uma pequena parte do produto funcionando e quando isso é feito, o Product Owner pode chegar em qualquer ponto do projeto e perceber que o investimento em mais um Sprint já não vale mais a pena como valia no início – porque as histórias que sobraram darão um retorno bem menor do que o valor investido em um Sprint – e ele pode decidir que é necessário encerrar o projeto por razões econômicas óbvias e partir para outro.

O ponto de vista do desenvolvedor

Os princípios de desenvolvimento ágil também não deixam dúvidas. Big Design Up Front (BDUF) é coisa de cascateiro, e as práticas de desenvolvimento como Test-Driven Development (TDD) fomentam justamente o desenvolvimento incremental.

Do ponto de vista do desenvolvedor ágil também é um erro desenvolver todo o design antecipadamente.

O ponto de vista do designer

Só depois de muitas conversas com o Cainã Nunes e o André Braz – dois dos melhores “criativos” que temos aqui na Globo.com – é que eu consegui entender o problema de verdade. Eu não sou nem de perto um especialista no assunto (e nem pretendo ser), mas vou tentar explicar o pouco que eu entendo.

Para entendê-los, precisamos entender a diferença entre “design de interface” e “design de UX”.

Desenhar uma tela qualquer é muito fácil. No início da minha carreira quando eu trabalhava em uma agência de desenvolvimento de sites cansei de mudar e algumas vezes até fazer layouts. Depois que você aprende a usar direitinho o Photoshop e o Fireworks é realmente muito muito muito fácil desenhar uma tela, desenhar objetos diversos e entregar qualquer coisa. Não que todos os designers façam isso, mas que é fácil fazer uma tela qualquer é.

O problema é que aqui na Globo.com nós não queremos fazer somente telas. Além do design e beleza em sí, estamos preocupados com a experiência do usuário (a famosa UX). Ao contrário de desenhar uma simples tela, projetar a UX é muito muito muito difícil. Em UX, não basta ter uma tela, ela precisa ser fácil de usar, os usuários precisam querer usá-la e a experiência de uso tem que ser memorável – porque isso fará com que os usuários queiram voltar. Isso é tão difícil de fazer que muitas vezes falhamos, mas essa é a nossa mentalidade e como queremos desenvolver nossos produtos.

Quando falamos de projetar a UX, vários fatores além do Photoshop ou Fireworks estão envolvidos (veja o experience design manifesto para ter uma idéia). Aspectos como ergonomia, sentimento e psicologia entram em cena. Alguns projetos que fazemos são testados exaustivamente com usuários comuns no laboratório de usabilidade, e mesmo assim continua difícil de alcançar o resultado que queremos.

Pense friamente e veja como todas essas “loucuras” fazem muito sentido. Independente do processo que usamos, não é isso que queremos dar para os nossos usuários nos produtos que desenvolvemos?

O problema

O problema é que para projetar a experiência do usuário, os designers acreditam que é difícil (ou impossível) pensar em pequenas partes do site e que é preciso pensar na experiência como um todo. Isso vai totalmente de encontro com a forma que o processo funciona e que os desenvolvedores trabalham…

Para ser muito sincero, eu não entendia porque eles não gostavam da idéia de ir refatorando o design e ir adaptando conforme as partes fossem sendo desenvolvidas. O que eu sempre entendi é que indivíduos e interações devem estar acima do processo, então ao invés de ficar procurando respostas no processo precisamos confiar nessas pessoas – que são especialistas no que fazem – e junto com elas encontrar uma saída.

Isso não nos exime da responsabilidade de fazê-los entender claramente como funcionam os processos e princípios de desenvolvimento ágil para que eles saibam o impacto das suas decisões e ajudem a encontrar uma forma de trabalhar que seja compatível com essa realidade.

Harmonia entre desenvolvimento e criação

Depois de muitas tentativas e erros, a forma de trabalhar mais próxima do ideal que eu consigo enxergar é uma mistura dessas três visões.

Os projetistas de UX podem e devem sempre pensar na visão do todo mas não necessariamente precisam entrar em todos os detalhes de cada uma das telas. Com a visão inicial do projeto os designers já têm muitas informações que precisam para começar a trabalhar na experiência do usuário e devem desde já pensar no produto como um todo, mas mais uma vez, isso não quer dizer que tudo precisa ser feito e pensado nos mínimos detalhes antes do projeto. Abaixo ao BDUF!

Na nossa equipe os designers têm feito sketches, wireframes e desenhos à mão para discutir funcionalidades e usabilidade. Muitas vezes isso é feito durante as discussões do Sprint planning e re-pensado algumas vezes durante o Sprint. Depois, durante o desenvolvimento, a cada história que vai sendo desenvolvida o time vai implementando junto com os designers, que vão fazendo as pequenas partes necessárias para aquela funcionalidade específica e ao mesmo tempo o design da experiência como um todo é continuamente revisto e refatorado para atender à visão do projeto.

A idéia é mais ou menos como a do cone da incerteza: no início do projeto você têm uma vaga idéia de como será na prática a experiência do usuário, e essa certeza vai continuamente aumentando até que depois de algum tempo (mais próximo do fim) você tem certeza absoluta de como ela será.

Ainda não estamos craques em fazer isso mas promete funcionar bem melhor do que tudo que já tentamos.

Concluindo

Você é realmente ágil quando não existe algum processo burocrático que te impede de fazer alguma coisa com mais eficiência. Criar um processo ou ambiente que impeça as pessoas de trabalhar ao invés de facilitá-las vai totalmente de encontro à agilidade.

Para citar um exemplo, o próprio criador do ScrumJeff Sutherland – achou melhor adaptar o processo na sua empresa para fazer o design das telas antes do desenvolvimento. Nessa empresa os sistemas são feitos para serem usados por médicos e eles vêem o sistema como algo que dificulta o trabalho (torna menos ágil), portanto, a usabilidade do software tem que ser perfeita. Sendo o design tão crítico e tão importante para o sucesso do projeto, eles decidiram se organizar para trabalhar com definição de telas e criação de protótipos antes do desenvolvimento. E não adianta achar que todos os projetos devem ser assim; cada caso é um caso!

As pessoas precisam conversar mais e entender as motivações das outras e o que as levam à tomada de decisão. Quando você consegue entender de verdade o lado do outro (dos designers no meu caso) você começa a entender quais são as reais motivações para o que ele está fazendo. O designer no meu time não queria atrapalhar o processo fazendo todas as telas antes, ele simplesmente queria fazer um trabalho espetacular de usabilidade e essa era a melhor forma que ele conhecia. Fazer um trabalho excelente de UX foi exatamente o que o gerente de UX pediu para ele e é essa a direção que a empresa quer seguir. Só depois que eu me dispus a entender como funciona a cabeça dele (e de todos os outros de UX) é que eu estou conseguindo pensar de outra forma. Agora existem muito mais chances que a adaptação que estamos fazendo no processo funcione melhor.

Então, respondendo a pergunta do post: como trabalhar com os designers? Pense fora da caixa! Aqui estão algumas idéias e opiniões, mas que eu aconselho é que cada time experimente e encontre a sua resposta.

Se você ficou decepcionado com a resposta e achava que eu ia te dar uma regra para ser seguida sem precisar pensar, talvez você esteja procurando nas metodologias ágeis a resposta errada e precise de alguma outra coisa que dê isso para você.

Test infection: por onde começar?

Sunday, March 30th, 2008

Fala GC!

Cara, o que voce faria se entrasse em um projeto para implementar umas melhorias, mas esse projeto não tivesse nenhum tipo de teste, o código não fosse testável e você soubesse que daqui a 3 meses ia sair do projeto? Você perderia tempo fazendo refactoring, implementando testes, configurando CruiseControl e tal, ou ia simplesmente ligar o foda-se???

Isso acontece pelo menos 32409 vezes todos os dias em algum lugar do planeta.

Os desenvolvedores acostumados a programar com testes têm uma dificuldade enorme de trabalhar em aplicações que não tem testes. A primeira coisa que os desenvolvedores mais experientes fazem quando pegam uma aplicação nova é olhar a base de testes. Por alí já é possível descobrir uma série de comportamentos e detalhes da implementação do sistema, bem como as intenções de quem o programou. Mas o que você faz quando cai de pára-quedas num projeto que não tem um mísero teste sequer? Você não pode deixar esse problema para outra pessoa? É você o infeliz que tem que resolver o problema e fazer a faxina?

Minha resposta para essa pergunta é bem simples: SIM, você é o infeliz que tem que resolver o problema.

<história>
Uma vez eu trabalhava numa empresa e meu chefe me pediu para fazer um protótipo de um sistema que integrava um website com um PABX para fazer determinadas tarefas. Como era um protótipo e eu só tinha duas semanas, eu fiz ZERO testes (e a aplicação funcionava por milagre divino). Só que para o meu azar, esse protótipo era para fazer uma demonstração para um cliente, que adorou a idéia e comprou na mesma hora! Como meu chefe achava que já estava parcialmente pronto e funcionando, meu prazo para terminar era de mais quatro semanas. Duas semanas depois eu estava desesperado por não conseguir avançar na aplicação e não conseguir fazer o negócio funcionar. Aconteciam bugs estranhos, daqueles que te fazem pensar que você está na profissão errada. Todos os dias eu me arrependia profundamente de ter deixado os testes para trás. Meu chefe ficou desesperado e colocou mais um desenvolvedor para me ajudar. No primeiro dia ele me perguntou: “GC, onde estão os testes para eu dar uma olhada?”. Er.. bom… não tinham testes… E eu fiquei totalmente desmoralizado, fui humilhado, massacrado e apanhei quase até a morte.
</história>

Hoje em dia não abro mão dos testes. Se você entregar uma aplicação que não funciona, a culpa é sua! Então, faça tudo que é possível para garantir que tudo esteja funcionando.

Finalmente, respondendo o e-mail do meu amigo acima (que não posso dizer o nome porque não tenho permissão), eis algumas dicas para você não ficar em maus lençóis:

Dica número 1: faça sempre o melhor que puder! Mesmo que você ache que vai ficar 2 semanas ou 3 meses em um projeto, seu gerente pode mudar de idéia e você pode acabar ficando bem mais tempo do que isso. Então, tire essa idéia da cabeça já e comece a se preocupar com os testes. E mesmo que você com certeza absoluta só fique 3 meses, como que você vai sair de cabeça erguida e com a certeza de que o que você fez está funcionando se você não tem os testes para comprovar?

Dica número 2: conserte as janelas quebradas. Se alguém chega na sua casa e metade das janelas estão quebradas, então não tem muito problema se quebrar mais uma. Porém, se todas as janelas estiverem impecáveis, quebrar uma janela é péssimo! Siga este mesmo princípio para o seu código, não tenha janelas quebradas. Se você tiver 90% de cobertura de testes, todos eles forem impecáveis e nenhum falhar no CruiseControl, o próximo desenvolvedor que chegar se sentirá na obrigação de manter tudo funcionando da mesma forma, porque esta é a cultura do projeto. Já se todos os testes estiverem quebrados ou não houverem testes, não faz a menor diferença.

Dica número 3: não abraçe o mundo com as pernas! Não precisa refatorar a aplicação inteira de uma vez, até porque você corre um grande risco de tudo parar de funcionar e você ser demitido, além de que não vai conseguir implementar as features. Neste caso, minha estratégia seria refatorar o código na medida que precisasse implementar as features. Faria o ciclo normal de TDD: implementaria os testes fazendo refactor na implementação para torná-la testável, implementaria a feature, garantiria seu funcionamento e depois um novo refactor para deixar tudo bonito.

Dica número 4: get them Test Infected! Faça um workshop com os outros desenvolvedores do time e mostre para eles a importância de escrever testes. Ensine-os a usar o CruiseControl, JUnit, JMock, injeção de dependência e tudo mais que for necessário para que os testes aconteçam. Mesmo que você “perca” dois ou três dias de trabalho, com certeza ganhará muito mais desse dia em diante.

<piada>
Dica número 5: só por via das dúvidas, para ajudar nos momentos de fraqueza, coloque alguém para te vigiar em tempo integral. O “Dijkstra is watching” é ótimo para isso, tenha ele sempre por perto.
</piada>

Tiny Types

Wednesday, October 3rd, 2007

Continuando na “luta” para criar sistemas mais fáceis de se entender, me lembrei de dar uma olhada nos Tiny Types apresentados pelo Darren Hobbs.

O CV tinha passado esse link há algum tempo e eu havia olhado superficialmente. Até que nessa história de fazer Fluent Interfaces e Domain-Driven Design acabei me lembrando que isso poderia ser útil.

Os Tiny Types enriquecem o domain model e trazem alguns outros benefícios legais citados pelo Darren em seu texto. Para as próximas features vou experimentar essa estratégia para ver no que vai dar…

Refatorando para Fluent Interface

Tuesday, September 25th, 2007

Ultimamente tenho passado boa parte do meu tempo trabalhando numa aplicação chamada WebMediaAPI. Trata-se de uma… ahm… API de uso interno que tem como objetivo padronizar, centralizar e facilitar o acesso à mídias e seu consumo em sites da Globo.com.

Por exemplo, quando o pessoal do G1 quiser colocar vídeos no seu site, ao invés de dar vários SELECTs em tabelas que eles não entendem e não conhecem, a idéia é que eles possam usar um JAR na aplicação deles que encapsula várias funcionalidades oferecidas pela nossa infraestrutura de WebMedia, simplificando o trabalho deles (pois não terão que descobrir como inventar a roda) e o nosso (centralizando e organizando o consumo de mídias na empresa).

No início do projeto um dos maiores desafios foi estabelecer como seria a fachada desta API. Nós tentamos alguns formatos e como precisávamos lançar logo a primeira versão acabamos optando por uma interface “tradicional” e simplificada. Para ter uma idéia melhor, veja o código para selecionar os últimos vídeos publicados do programa “Altas Horas”:

int quantidade = 5;
long programaId = 456;
Set midias = new HashSet();
 
WebMediaServices webMediaServices = WebMediaFactory.getServices();
List idsMidias = webMediaServices
	.getIdsUltimasMidiasPublicadasPorPrograma(quantidade, programaId);
 
for (Iterator iter = idsMidias.iterator(); iter.hasNext();) {
   Long midiaId = (Long) iter.next();
   Midia midia = webMediaServices.getMidia(midiaId.longValue());
   midias.add(midia);
}

Não é muito difícil entender o funcionamento deste código… Só que ele poderia ser muito melhor!

Esta interface pode até funcionar mas não é nem um pouco intuitiva. A classe WebMediaServices como pode-se imaginar ficou com dezenas de métodos e virou basicamente um grande saco de funcionalidades. Qualquer método simplesmente ficava nesta classe – o que não é nem um pouco elegante.

Depois de algum tempo tive a idéia de refatorar a API para uma Fluent Interface. A idéia é tentar fazer algo que se assemelha a uma DSL interna, que não é nada mais do que uma API com nomes interessantes. Ao invés de um saco de métodos a WebMediaAPI agora é acessada através de uma interface semânticamente organizada e seu design é pensado para ser legível e… fluente!

Veja como ficou o novo código para selecionar os últimos vídeos publicados do programa “Altas Horas” (exatamente a mesma coisa que o código anterior faz):

Long altasHoras = new Long(456);
Set videos = WebMediaAPI.videos().recentes().doPrograma(altasHoras);

Bem mais elegante!

O lado negativo é que quanto mais fácil a API torna-se para o cliente mais difícil torna-se sua implementação. Construir uma fluent interface muitas vezes me fez perder algumas horas pensando como certas coisas seriam feitas, mas eu gostei do resultado final e acho que para esse tipo de aplicação valeu a pena.

Para mostrar a diversidade e simplicidade da nova API, veja mais alguns exemplos (repare que eu não tenho que dizer nada sobre o que eles fazem para você entendê-los):

// exemplo 1
Set programas = WebMediaAPI.programas().comTitulo("Fantastico");
 
// exemplo 2
Long multishow = new Long(123);
Set videos = WebMediaAPI.videos().favoritos().doCanal(multishow);
 
// exemplo 3
Long destaquePrincipalGloboVideos = new Long(123);
Integer quantidadeMaxima = new Integer(10);
Set videos = WebMediaAPI.videos().relacionados().aoCanal()
	.doVideo(destaquePrincipalGloboVideos, quantidadeMaxima);

Ainda temos um longo caminho pela frente e muita coisa ainda será melhorada, mas já dá para perceber uma difirença significativa entre as duas versões.

Slides da palestra sobre TDD no RioJUG

Wednesday, June 20th, 2007

Estou disponibilizando os slides da palestra sobre Desenvolvimento Guiado por Testes apresentada no RioJUG no dia 19/06/2007.

Desenvolvimento Guiado Por Testes
View SlideShare presentation or Upload your own. (tags: tdd bdd)

Como o tempo ficou curto lá na palestra acabei não apresentando o último slide que contém alguns links interessantes para quem quiser conhecer mais sobre o assunto:

Otimização prematura

Friday, June 15th, 2007

Dando uma olhada em uns projetos que estavam no meu Eclipse encontrei um projeto antigo de uma empresa que eu trabalhei. Esse projeto teve o desenvolvimento mais curto da história: 1 dia! É sério, ele acabou no mesmo dia que começou por uma série de razões.

Mais isso foi só uma pequena introdução, a história de verdade não é essa. Dê uma analisada num trecho de código deste projeto que foi desenvolvido por alguém lá da equipe (detalhe: leia atentamente o comentário):

public class Usuario implements BussinessObjectModel {
 
    protected UsuarioDTO usuarioDTO;
 
    public void login() throws Exception {
        if(this.usuarioDTO == null || this.usuarioDTO.getSenha() == null || this.usuarioDTO.getUsuario() == null) {
            throw new Exception("Erro");
        }
 
        /**
         * TODO: codigo do login.
         * ir no banco de dados, decriptar a senha, comparar
         * com o cara. logar no JMS, mandar um SMS, atualizar
         * o cache de usuarios, fazer uma chamada ejb remota
         * dizendo que o usuario entrou.
         */
    }
}

Donald Knuth já dizia que a otimização prematura é a raiz de todo o mal. Mas acho que quando ele disse isso jamais imaginaria uma otimização TÃO prematura. Em toda a minha vida esse foi um dos maiores exemplos de overdesign que eu já ví!

Repare: era o primeiro dia do projeto. Nem sabíamos direito o que precisava ser feito e o cara já decidiu que a aplicação deveria ter DTOs, JMS, EJB e cache de usuários… Sem sequer pensar no problema o programador decidiu adicionar uma complexidade enorme e desnecessária ao sistema.

Quando se desenvolve um projeto de software, a primeira coisa que deve-se fazer é atender aos requisitos funcionais do cliente da forma mais simples e rápida possível. Em seguida faz-se refactoring do código para que ele seja melhorado e no futuro possa se adaptar melhor a eventuais mudanças. E só.

Isto significa que neste momento você não se preocupa com cache, por exemplo. Se por acaso algum dia houverem problemas de performance, aí sim, pensa-se em cache, distribuição da aplicação e etc. Neste caso esta aplicação estava prevista para ter pouco mais de 10 usuários simultâneos, uma quantidade de acessoss ridícula para se pensar em otimização.

Os desenvolvedores têm uma mania horrorosa de overdesign, especialmente os desenvolvedores Java. É preciso parar de tentar adivinhar o futuro e se concentrar mais nos problemas que precisam ser resolvidos agora. Deixe os problemas do futuro para serem resolvidos no futuro!

Refatorando para aspectos

Thursday, May 10th, 2007

Acabo de assistir no InfoQ uma apresentação do Ramnivas Laddad sobre refatoração de aplicações para AOP.

Assistindo a explicação dele dá para entender a linha de raciocício que ele segue e a quantidade de possibilidades que a programação orientada a aspectos traz. Realmente é um saco fazer repetidamente código para controlar permissões, erros, transações, concorrência e outros mais. Com AOP a quantidade de esforço para implementar este tipo de situação é reduzida consideravelmente e este artigo trata exatamente disso: reconhecer trechos de código que são candidatos a serem reescritos para se tornarem aspectos.

Porém eu acho que deve-se tomar muito cuidado ao sair refatorando a sua aplicação para aspectos. Imagina um sistema com centenas de classes que possuem dezenas de aspectos diferentes. A impressão que eu tenho é que se você tem aspectos demais o sistema pode ficar até mais difícil de programar. Isto porque se você tem código fora do método sendo executado “dentro” do método, a clareza em relação ao que ele faz fica reduzida. Multiplique isso por centenas de classes e métodos e você tem um monstro indomável.

Mesmo assim a abordagem dele é bem interessante pois quando utilizada corretamente estimula a produção de CÓDIGO com lógica de negócio ao invés de código que não tem nada a ver com o que o sistema realmente faz, tornando o desenvolvimento mais produtivo.