quarta-feira, 18 de maio de 2011

Xtreme Programming - On Demand

Olá pessoal, estou de volta e dessa vez vou falar sobre um dos temas mais polêmicos do Extreme Programming que é o Pair Programming.

O Pair Programming consiste em dois desenvolvedores atuando no mesmo problema no mesmo computador, sendo um o Piloto e o outro o Navegador. Semelhante ao que temos nas corridas de Rally :p .

Bom, o primeiro grande desafio da programação em par é convencer os nossos chefes de que não será improdutivo manter duas pessoas no mesmo computador full-time. O segundo desafio é a equipe, infelismente nem todos estão aptos a trabalhar com Pair Programming. Muitos, ao invés de serem navegadores, serão simplesmente passageiros, enquanto o piloto desenvolve o passageiro apenas contempla a paisagem e não presta atenção nem mesmo no caminho que está sendo tomado.

Pois bem, na minha opnião, não é necessário ter dois desenvolvedores juntos full-time nas tarefas do projeto, eu acredito mais no Pair Programming On Demand, ou seja, para tarefas mais específicas, desafios maiores, requisitos que possuem maior risco, complexidade. Até porque, pensem comigo, para que ter dois desenvolvedores na implementação de uma solução simples, getters and setters, binds, dao's, ou seja, tarefas rotineiras que já estão no sangue da equipe de desenvolvimento, nestes casos penso que Pair Programming não agrega muito.

Agora quando temos uma rotina complexa, onde temos um grande risco envolvido, ou uma refatoração mais delicada, aí sim, acho que é muito válido a aplicação do Pair Programming para que o problema, o desafio seja resolvido, por isso que digo que acredito mais no Pair Programming On Demand, ou seja, aquele que só é aplicado quando surge uma demanda específica que justifique duas cabeças pensando no problema.

Os defensores mais ferenhos da técnica podem dizer que assim não temos o código completamente compartilhado pela equipe, ou que não inibimos o XGH, ou que decisões podem ser tomadas por um único programador.

No caso das decisões de design, eu diria que o ideal não é nem envolver só dois desenvolvedores mas todos. Em nosso projeto o que tem acontecido é que quando detectamos algum ponto que pode ser melhorado ou quando nos deparamos com algum requisito que demandará a aplicação de algum pattern ou criação de alguma biblioteca nova, sentamos e discutimos.

Com isso, quando forem aplicar Extreme Programming, como tudo na vida, usem e abusem do bom-senso e preste atenção na composição da equipe, certifique-se que os são porcos e não galinhas, e para perceber isso basta observar o comportamento dos desenvolvedores quando não estão pilotando, ou seja, se ele fizer um papel de navegador, tem grandes chances de ser um porco, se fizer papel de passageiro, tem grandes chances de ser galinha.

É isso pessoal, não tenham medo nem vergonha de "parear" em suas equipes, sem dúvida nenhuma duas cabeças pensam melhor do que uma, mas tenhamos bom-senso, pares para get e set, factories, singleton, binds e outras atividades tão triviais do nosso dia-a-dia... na minha opnião não fazem sentido.

Um grande abraço.

quarta-feira, 27 de abril de 2011

Testes Unitários

Olá pessoal, Apesar do tempo longe ainda estou vivo. Pois bem, as últimas semanas tem sido muito corridas, em especial por dois fatos: Testes e GUI.
Bom, em relação a GUI vou deixar para outro post. Hoje quero falar sobre testes unitários.

Há um tempo ouvi falar de um tal de teste unitário. Um negócio meio estranho de escrever um código para testar seu próprio código. Uma parada meio louca mas que todo mundo diz que é bom e funciona =). Talvez essa seja a sensação que a maioria dos programadores tem quando lê sobre testes unitários a primeira vez.
Hoje muito se fala em teste unitário, mas acredito que infelizmente muita gente ainda não faz. No projeto em que eu estava anteriormente, era bem complicada a adoção de testes unitários, não tínhamos um modelo bem definido, não tínhamos separação lógica de camadas, a GUI tinha praticamente toda a inteligência do negócio, a persistência também estava na GUI, sem contar na ferramenta defasada, enfim, um clássico projeto legado que precisa ser mantido e evoluído ao mesmo tempo. Por este cenário, era quase utópico pensar em testes unitários, em cobertura de testes então, era quase impossível.
Pois bem, neste novo projeto, produto novo, sendo concebido do zero, seguindo uma série de boas práticas, guiados pelo DDD, não tínhamos porque não fazer testes unitários. Primeiramente pensamos logo no TDD, mas como não tínhamos muita experiência com testes unitários, resolvemos adotar o teste unitário, mesmo que depois do código pronto, para depois, dentro de alguns sprints, adotarmos o TDD.
Começamos o projeto, escrevendo nossos testes baseado em alguns artigos que encontramos. Procurei alguns livros mas não encontrei nenhum aqui no Brasil que me despertasse interesse. Tinham alguns em sites lá de fora mas o prazo de entrega era muito longo, e não poderíamos esperar para começar a escrever, decidimos então fazer com o pouco conhecimento que tínhamos, as dúvidas pesquisaríamos e iríamos vencendo os obstáculos a medida que fossem aparecendo, além de refatorar os mesmos quando necessários.
Iniciamos os sprints, escrevendo nossos testes com o NUnit, adquirimos o NCover para nos auxilliar na cobertura, para identificar o que não estava coberto por testes unitários, bom, mas isso não vem ao caso pois cobertura de testes vai ser assunto para outro post.
Durantes nossos testes, não tivemos poucas dificuldades, tivemos MUITAS. A prática traz a excelência e como não tínhamos prática, estávamos muito distante da tal excelência(como ainda estamos).
Vou compartilhar agora alguns questionamentos que passamos:
· “O que testar ?“ - Apesar de ser um questionamento simples, tivemos esta dúvida. Testamos a persistência, o facade e o repositório ? Não parece redundante ? Mas pode haver alguma falha de comunicação entre as camadas, se não testarmos não pegaremos estes erros ? Devemos testar os Get e Set do modelo ? e por aí vai...

“Como testar a persistência ?” - Se temos uma camada única de persistência, usando NHibernate, não seria redundante escrever os testes de update, delete, getById, getList etc... para cada modelo ? Não teríamos apenas que testar estes métodos uma vez ? Não teríamos apenas que testar os mapeamentos dos modelos ? Não teríamos como fazer isso de forma automática ? Além disso, temos que garantir que o banco de dados seja o mesmo ao final do teste, para não impactar testes futuros, como gerar estes dados ? Como garantir a estabilidade do ambiente ? e por aí vai....

· “Usar ou não usar Mocks” – Quando devemos usar Mocks ? Para que eles servem ? Usando Mocks não estamos fazendo com que o ambiente de teste seja “forjado”, fugindo da realidade ? e por aí vai...

· “Que padrões adotar para testes” – Uma classe de teste para cada classe de negocio ? Quais padrões de nomenclaturas ? Como separar os namespaces e assemblies de testes ? e por aí vai...

Nós sabíamos que não seria fácil, o começo é a parte mais traumática de qualquer novo desafio, e não contentes com estas dúvidas, fomos atrás de respostas. Durante nossas pesquisas, vimos inúmeros exemplo simples, como por exemplo, testando os Get e Set, testando o somar, subtrair, testando uma rotina de desconto, validação de dados, enfim... De certa forma nos decepcionamos, a sensação que tivemos é de que testes unitários, cobertura de testes era uma lenda. Todo mundo dizia que era bom, todo mundo dizia que era importante, mas ninguém dizia como fazer de fato em um projeto real.
Pois bem, não desistimos, sabíamos da importância dos testes, sabíamos que só dependia de nós. Estudamos mais um pouco, erramos mais um pouco, refatoramos muito e continuamos a escrever nossos testes.
Na falta de padrões de mercado que nos dessem segurança, seguimos de acordo com o que achávamos ser o mais correto e coerente baseado em tudo o que havíamos lido, feito e discutido. Decidimos que todas as classes seriam testadas, criamos um método genérico para testar o mapeamento de todas as classes no NHibernate, separamos os testes em dois assemblies, um de testes de interface e outro para os testes do Selenium, para a nomenclatura usaríamos em português de forma mais clara possível, mesmo que as vezes o nome fique gigante rs.
Bom, seguimos escrevendo nossos testes, buscando o máximo de cobertura possível. Ainda existem alguns desafios como por exemplo a automatização dos teste de GUI, estamos amadurecendo no uso do Selenium e em breve postarei sobre isso.
Bom, não sei se consegui transmitir aqui a mensagem desejada. O que eu queria deixar claro é que fazer testes unitários NÃO é tão fácil quanto parece. Existe uma grande possibilidade de você desanimar e chutar o balde diante das dificuldades iniciais, e continuar desenvolvendo sem testes unitários, a sensação que você pode ter no inicio é de que isso é uma lenda e não funciona.
Mas eu lhes digo, é apenas uma sensação inicial, testes unitários funcionam e eu não consigo me imaginar desenvolvendo sem eles. Em breve postarei aqui sobre os benefícios que percebi após adoção dos testes unitários.
Meu recado final é: Façam testes unitários. Superem as dificuldades. No início eles não serão os testes mais elegantes e eficientes do mundo, mas com o tempo você pega o jeito, refatora os mesmos e logo logo não conseguirá mais programar sem eles, portanto, se for para desenvolver um projeto de software, faça testes unitários, sempre que possível.

P.S.:É claro que estes testes devem estar em um ambiente automatizado, com cobertura medida e tudo mais, mas isso é assunto para um outro post, neste limito-me a algumas das experiência vividas com Testes Unitários, sem nem mesmo entrar no mérito do TDD ainda. Caso alguém tenha um livro para indicar sobre testes unitários, padrões e boas práticas de testes unitários, TDD para nos indicar, fiquem a vontade =) =). Fiquem a vontade também para compartilhar suas experiências, vamos mostrar para o mundo que SIM, teste unitário funciona e é fundamental para o desenvolvimento de softwares de qualidade.

Até logo pessoal, um grande abraço.

sábado, 26 de março de 2011

De volta, de novo, novamente, Again!!!

Olá pessoal, esse meu último afastamento foi o maior de todos, alguns meses se passaram sem posts no blog. :/

Mas agora, estou "de-volta, de-novo, novamente, Again!!!", a redundancia é proposital, para enfatizar as ida

Pois bem, agora estou de volta com força total. Neste post vou atualizar vocês com algumas coisas que aconteceram nestes últimos tempos.

Para começar, quem conhece sabe que a adoção de métodos ágeis não é fácil. Eu acredito até que seja mais dificil do que um processo formal, ditado por regras e documentações extensivas.
Até mesmo em um ambiente digamos "propício" a uma metodologia ágil, com uma equipe experiente, motivada, uma liderança forte e bem definida, com um cliente participativo no projeto, mesmo neste ambiente, é complexo adotar metodos ágeis e suas técnicas e práticas.

Agora imaginem somar a esta complexidade, um projeto legado que precisa ser mantido e evoluído, em paralelo com outro projeto que está sendo concebido. Consegum imaginar este cenário ? Um único líder e uma única equipe, para lidar com os dois projetos.
O projeto A que já está no mercado em dezenas de clientes, com uma certa demanda de manutenção e evolução, e o projeto B, que está sendo construído em paralelo e conta com um cliente interno. Além disso, o projeto A é em Delphi voltado para Win32 e o projeto B é em .NET voltado para WEB.

Bom, até um tempo atras eu imaginava que isso era possível, talvez por otimismo, talvez pela motivação do desafio, ou por qualquer outro motivo, eu acreditava que era possível no meu cenário(talvez em outros cenários seja mais viável), vi que estava equivocado e diante disso, compartilho com vocês algumas dificuldades que encontrei:
  • Manutenção, ainda mais de projetos legados, são complicadas, muitas vezes imprevisíveis. Além disso, a correção de erros precisa ser priorizada, dessa forma os SLA's de manutenção acabam interferindo no desenvolvimento das stórias do sprint.
  • A mudança de foco entre problema, tecnologia, cenário, plataforma do projeto A e do B, afetavam a produtividade e o crescimento da equipe. Ao invés de termos uma equipe com aquela tradicional curva de aumento de produtividade ao longo dos ciclos, tinhamos uma equipe com pouco ganho de produtividade, pois ela acabava não se dedicando inteiramente a um único projeto.
  • A gestão de tarefas fica mais complicada, pois temos que misturar tarefas de dois projetos diferentes, com prioridades e complexidades diferentes, com processos e equipes de homologação diferentes.
  • Algumas demandas de customização, prendiam membros da equipe por dias, atrapalhando a evolução do ciclo.
Motivado pelo desafio, buscamos customizações no processo e no ambiente, de forma a suportar este cenário. Eu admito que o resultado não foi ruim, mas estava distante do ideal. O Projeto A estava controlado com as customizações e correções sendo atendidas no prazo. Por outro lado o Projeto B estava se movimentando a 30km/h, mas o product owner precisava que este projeto se movimentasse a 100km/h.

Diante disso, em uma reunião com o Product Owner, foi decidido pelo caminho talvez mais óbvio: A divisão da equipe. Definimos um período de transição, e uma data de corte, quando a equipe do projeto B seria desligada do projeto A. Fiquei como ScrumMaster do projeto B, sem ter que me preocupar mais com o legado e as manutenções do projeto A. Ou seja, a partir de agora, eu e a equipe poderiamos ter Foco.

Escolhi os membros que melhor se enquadravam e fizemos a migração.

Desde então retomamos de forma mais consistente a adoção de Agile e o projeto está começando a ganhar mais volume e força.

Nos próximos posts comentarei mais sobre essa nossa nova experiência, falando sobre as práticas que estamos utilizando, os padrões que estamos seguindo, as dificuldades que estamos encontrando, enfim, sobre nossa experiência Agile.

Por hora é isso, desculpem-me pelo afastamento, e espero nos próximos dias, semanas, meses, anos, compartilhar muitas experiências de adoção de métodos ágeis com vocês.

Abraço.