Return Of Investment

“Um dos principais objetivos do Scrum é entregar o maior valor de negócio para o cliente no menor tempo possível. Quanto mais dinheiro o cliente puder ganhar e quanto mais rápido, melhor. Sendo assim, o P.O. sempre deve pensar na melhor forma de maximizar o ROI – retorno sobre o investimento.”

Recomendo muito a leitura dos posts:

Quando Usar Objetos Mocks?

Precisei fazer alguns objetos mocks no trabalho e achei um artigo interessante sobre uso de frameworks de Objetos Mock. Segue o artigo do K Scott Allen:

 

Mocks – Esta é uma Questão de Quando.

Ross Neilson lembrou-me uma pergunta que me deixou enforcado: “Quando eu uso um Mock Framework?”

 

Se você perguntar “quando”, a resposta é provavelmente “não agora”. Eu sinto que framework de objetos de mentira (Mock Objects) é algo que você tem que evoluir.

Primeiro, nós podemos falar sobre Mocks em geral. Algumas pessoas tem a concepção que Objetos Mock são apenas útil se você precisa simular uma iteração com um recurso que é difícil usar em testes de unidade – como um objeto que comunica com um servidor SMTP. Isso não é verdade. Colin Mackay tem um artigo sobre mocks que demonstra outros cenários comuns.

 

  • O objeto real tem comportamento não determinístico
  • O objeto real é difícil de configurar
  • O objeto real tem comportamento que é difícil de acionar
  • O objeto real é lento
  • O objeto real é uma interface de usuário
  • O objeto real usa uma chamada de retorno (call back)
  • O objeto real ainda não existe

 

Se dermos um passo para trás e generalizarmos essa lista, diríamos que test doubles são úteis quando você quer isolar um código do seu teste. Digamos que estamos escrevendo testes para um componente de negócio. Nós não gostaríamos que o teste falhe quando alguém introduzir um código ruim de um serviço de auditoria usado pelo componente de negócio. Nós somente queremos testar a falha quando alguma coisa está errada com o próprio componente de negócio. Fornecer um mock para o serviço de auditoria nos permite isolar o componente de negócio e controlar qualquer estímulo que o componente pode receber desse serviço de auditoria. Quando você começar a sentir a dor de escrever vários test doubles na mão, você vai saber que necessita de um framework de Objetos Mock.

 

Mocks não são somente sobre isolamento, no entanto. Mocks tem também um papel no desenvolvimento orientado a testes (TDD), o qual se refere Colin no último ítem. O autor de Mock Roles, Not Objects” diz que mocks são:

“Uma tecnica para identificar tipos baseado em papéis que o objeto desempenha em um sistema… Em particular, nós agora sabemos que o maior benefício de Objetos Mock é aquilo que originalmente chamamos de descoberta de interfaces”

 

Usar um framework de Objetos Mock no TDD permite um contínuo, top-down desing de software. Muitos fãs de TDD sabem que necessitam de um framework de Objetos Mock um dia.

 

Mas frameworks de Objetos Mocks não são complexos?

 

 Essa é outra questão que eu fui questionado recentemente. Frameworks de Objetos Mocks são atualmente mais simples e expõem uma pequena API. Existe complexidade, porém, não no framework em si. Como eu disse anteriormente, eu penso que existe um caminho que você segue para evoluir no uso de frameworks de Objetos Mock. Um típico time de um projeto usando framework de Objetos Mock tem vivência com TDD e Containers de Inversão de Controle. Tentar ter velocidade com todos esses tópicos de uma vez pode ser esmagador. 

 

Existe também alguma complexidade no uso de mocks efetivamente. Em Mocks and the Dangers of Overspecified Software, Ian Cooper diz:

 

“Quando você muda a implementação de um método através de um teste, mocks podem quebrar porque você pode fazer chamadas adicionais ou diferentes para o componente dependente que está sendo mocado.  …  O mock começou a fazer nosso software mais resistente a mudança, mais lento, e isso aumentou o custo para refactoring. Como a mudança se tornou mais caro, nós ficávamos resistentes a fazer isso, e corremos o risco de começar a construir débitos técnicos (technical debt). As vezes um teste quebra, quando desenvolvedores mudam o domínio, ou mudou o modo de como fomos fazer a persistência, sem alterar o teste em primeiro lugar, porque eles ficaram frustados de como isso deixou mais lento o seu desenvolvimento. Os mocks se tornaram um impedimento ao progresso.”

 

Framworks de Objetos Mocks fazem fáceis interações baseada em testes, mas podem também levar a problemas que o Ian Cooper descreve acima. Aqui está mais algumas leituras para esse tópico:

 

Guidelines to Using Interaction Based Testing

Why Mock Frameworks Suck

 

Em resumo, frameworks de Objetos Mocks (por exemplo JMock, EasyMock, and NUnit) não são para tudo, Você deverá saber quando  necessitar de um.

Blog Visão Ágil

Estou participando, com bastante satisfação, como autor no blog da Visão Ágil, que é um canal para debater sobre metodologias ágeis. Foi inaugurado a pouco tempo e já tem assuntos muito interessantes. Segue o link da inauguração:

 

http://www.guj.com.br/posts/list/97347.java;jsessionid=14ijm34a3rnrx.jetty1#523556

Arquitetura do LinkedIn

Esse post é baseado em um artigo do Hurvitz sobre a arquitetura do LinkedIn.

No JavaOne 2008, funcionários do LinkedIn apresentaram duas sessões falando sobre a arquitetura desse site de relacionamento. Podemos ver os vídeos nos links abaixo:

 

O LinkedIn é um dos maiores sites de relacionamento na Internet. Trata-se de uma aplicação Web 2.0 em Java.

Algumas Estatisticas:

 

  • 22 milhões de membros
  • 4+ milhões de únicas visitas por mês.
  • 40 milhões de visualizações por dia.
  • 2 milhões de buscas por dia.
  • 250K de convites enviados por dia.
  • 1 milhão de respostas postadas.
  • 2 milhões de mensagens de e-mail por dia.
Software:
  • Solaris (rodando em plataforma Sun x86 e Sparc)
  • Tomcat e Jetty como servidores de aplicação.
  • Oracle e MySQL como DBs
  • Não usam ORM (como o Hibernate); they use puro JDBC
  • ActiveMQ para JMS. (Particionado pelo tipo de mensagem. Usando MySQL.)
  • Lucene como uma engine de buscas.
  • Spring entre as camadas.
Arquitetura do Servidor
(2003 a 2005)
  • Uma aplicação monolítica.
  • Um único banco de dados (Core Database)
  • O gráfico de rede cacheada em memória no The Cloud
  • Busca de membros usando Lucene. Rodando na mesma máquina que o The Cloud, porque a busca de membros deve ser filtrada de acordo com a busca do usuário de rede.
  • Aplicação Web atualizando o banco de dados principal (Core Database) diretamente. O Core Database atualiza o The Cloud.
( 2006 )
  • Adicionado réplicas de banco (Replica DB’s) para reduzir a leitura no Core Database. As réplicas contém dados read only. Um servidor RepDB gerencia atualizações das réplicas.
  • Movido a engine de Buscas para fora do The Cloud, passando a ser contido em seu próprio servidor.
  • Mudou o lugar onde as atualizações eram feitas, adicionando o Databus. Este é um componente central que distribui atualizações na base. O novo fluxo de atualizações seria:
  1. Alterações originadas da Aplicação Web.
  2. A Aplicação Web atualiza o Core Database
  3. O Core Database envia atualizações para o Databus
  4. O Databus envia as atualizações para: O Replica DB’s, para o The Cloud, e para a engine de Busca
( 2008 )
  • A Aplicação Web não faz mais nada por si só. Ela divide parte das lógicas de negócio em Serviços.
  • A Aplicação Web se torna apenas uma GUI (interface) para o usuário, mas agora ela chama serviços para manipular Perfil, Grupos, etc.
  • Cada Serviço tem seu próprio banco de dados de domínio, ou seja, são partições verticais.
  • A arquitetura permite outras aplicações (através da aplicação Web) acessar o LinledIn. Permite adicionar aplicaçnoes para Recrutar pessoas, adicionar pessoas, etc.
Mais detalhes sobre o The Cloud pode ser encontrado no blog citado no início. O Cache foi implementado em C++ em vez de Java por duas razões.
  • Usar o mínimo de RAM possível.
  • Pausas de Garbage Collection estavam matando eles. [Porém o GC está sendo melhorado desde 2003, isso ainda seria um problema hoje?]
Aparte eles usam o Ehcache para cachear perfis de membros (cerca de 22 milhões de membros). Eles tentaram cachear usando o algoritmo LFU (Least Frequently Used), mas consideraram que o EHcache as vezes bloqueava por 30 segundos para recalcular o LFU, então eles mudaram para o LRU (Least Recently Used)
Arquitetura de Comunicação:
Esse serviço é referente a mensagens permanentes, por exemplo mensagens e e-mail.
  • O sistema inteiro é assíncrono e usa JMS pesadamente.
  • Clientes postam mensagens via JMS
  • Mensagens são depois roteadas via um roteador de serviços para o mailbox apropriado ou diretamente para o processo de email.
  • Entrega de mensagens> tanto Pull ( clientes solicitam suas mensagens), ou Push (envio de email)
  • Eles usam o Spring, com o proprietário LinkedIn Extenção Spring. Usam HTTP-RPC.
Serviço de Actualização na Rede:
Esse serviço é responsável por notificações de vida curta, por exemplo atualização de status de seus contatos. O LinkedIn trabalhou em três grandes interações, detalhadas no blog no início.
Alguns aspectos interessantes da aplicação:
  • Mais de 6500 testes de unidade e de integração.
  • 500 Html Unit testes.
  • Uso de integração continua (Hudson).
  • Uso de EasyMock.
A apresentação termina com algumas dicas sobre escalabilidade. São velhas mas boas:
  • Não pode usar somente um banco de dados. Use muitos banco de dados, particionados horizontalmente e verticalmente.
  • Por causa da partição, esqueça sobre integridade referencial ou cruzamento de domínios com JOINs.
  • Esqueça sobre 100% de integridade de daos.
  • Em larga escala, custo é um problema: hardware, bases de dados, licenças, armazenamento, poder.
  • Depois que você for grande, spammers e scrapers vêm atrapalhar.
  • Cache!
  • Usar fluxos assíncronos.
  • Relatórios e Análises são um desafio, considere eles quando desenhar o sistema.
  • Espere que o sistema falhe.
  • Não subestime a sua trajetória de crescimento.

Comportamento de Software

 Behaviour-Driven Development (BDD) é o desenvolvimento de software dirigido ao seu comportamento. É a união de desenvolvimento guiado por testes (TDD) e Design dirigido ao domínio da aplicação (DDD).

Para entender direito o que é BDD é necessário comentar sobre TDD e DDD. Nesse post quero focar no TDD. Um assunto tão importante como esse merece muita atenção!

Quando acontece um bug num software é bastante comum os desenvolvedores gastarem mais tempo tentando achar o erro do que consertar o erro em si, principalmente se o sistema não tiver testes automatizados.

O TDD é uma prática usada por times que seguem Extreme Programming. Desenvolvedores que não usam essa prática se encaixam em um dos itens abaixo:

  • Tem preguiça de fazer testes
  • Faz os testes no final
  • Não conhecem os benefícios de o TDD trás.
Existem desenvolvedores que confiam tanto no seu trabalho que deixam para outros testarem o que desenvolveu. Porém um bug pode não ser pego no teste de outros e ocorrer quando estiver em produção.
Os que deixam os testes para o final podem não lembrar de testar todos os cenários. E se ocorrer atrasos no projeto o primeiro que vai ser cortado são os testes.
Para quem não conhece os benefícios do TDD fale a pena comentar um pouco do assunto.

Iniciar essa prática pode parecer um pouco difícil e chato, mas para a equipe de XP isso se torna muito natural. Todo código implementado deve coexistir com um teste automatizado, para garantir o funcionamento do software com a entrada de novas funcionalidades. Esses testes automatizados garantem a qualidade do software pois, se uma nova codificação afetar alguma regra de negócio, o teste deve instantaneamente apontar o problema antes que o release seja entregue. Quando essa automatização existe, os desenvolvedores ficam com mais coragem de alterar uma parte do código que ele não desenvolveu e eles tem mais confiança de fazer refatorações necessárias para melhorar o código. A Refatoração é muito importante seja para facilitar a manutenção do sistema ou para melhorar a performance do código, mas que seja feira sem alterar a funcionalidade do software. Geralmente a gente refatora quanto encontramos códigos duplicados, pouco legíveis, mal codificados, sem padronizações, lentos etc.

Primeiro implemente o que (comportamento) você quer testar, e execute testes de sucesso que garantam falhas do sistema e testes de sucesso que garantam o bom funcionamento. Depois disso você implementa a funcionalidade em questão.

Uma boa prática de trabalhar com TDD é fazer o que o pessoal de XP chama de seguir “passos de bebê”. O benefício disso é que quando você faz um teste para um software que tem poucas linhas é bem mais difícil de você ter inserido um bug. E a medida que a funcionalidade vai crescendo os testes automatizados tem que continuar executando, tanto os de falha quanto os de sucesso.

Fazer TDD não é apenas testar a aplicação e sim fazer um design simples. Muitos problemas de acoplamento das suas classes serão percebidos quando escrever um teste. TDD é muito relacionado com refactoring, tornando o código fácil de ler. O fato das pessoas não saberem o que testar e como testar torna uma barreira para fazer os testes, mas depois de se conhecer os benefícios e começar a praticar, o desenvolvimento guiado por testes tente a ser uma maneira natural de pensamento. 

“Nos dias de hoje, é irresponsabilidade um desenvolvedor entregar qualquer linha de código sem que exista um teste unitário para comprovar o seu funcionamento” frase de Bob Martin

Existem basicamente dois tipos de testes, os testes de unidade e os testes de aceitação (integração). Os testes de unidade seriam para testar os métodos de uma classe. Já os de integração tem como objetivo validar a integração das classes que implementam uma funcionalidade, atendendo as necessidades de maneira correta. Os testes de integração, na maioria dos casos, são descritos pelos clientes, mas quem implementa são os desenvolvedores.

Para fazer testes automatizados temos muitas ferramentas disponíveis, basta usá-las.

Testes unitários, em Java, temos JUnit, UnitNG, JMock. Para testes de integração temos o Selenium, Fit, Fitnesse. Ferramentas de BDD JBehaveJDavebeanSpecInstinct.

Em Ruby on Rails temos autotest para automatização dos testes. Para BDD tem ótimas ferramentas como RSpec Shoulda.

Em Javascript, para o JQuery, temos o JQunit. Para BDD tem o JSSpec.

Para Integração Contínua tem o CruiseControl.

Para verificar a cobertura de testes temos o EmmaCloverJCover.

Precisei fazer uma refatoração num sistema que não tinha testes unitários e as classes eram bastante acopladas. Mas isso não foi problema para eu criar os testes. Usei o JMock e criei objetos de mentira para simular outras classes que não era minha intenção testar. O JMock pode ser usado para simular uma classe que faz acesso a banco, HTTPRequest ou qualquer outra classe do seu sistema. Um exemplo de uso nesse post.

Um excelente exemplo de TDD pode ser lido nesse post da Improve It.

Uma das ferramentas que mais gostei foi o Selenium. O Selenium-IDE funciona como um robozinho que grava as ações em uma tela. Por exemplo o click em um botão deve trazer uma lista de resultados. Se ao disparar o teste do botão a listagem não aparecer, o Selenium-IDE avisa que tem erro no sistema. A ferramenta pode disparar o mesmo teste em vários browsers diferentes.

Quando pensamos em qualidade no software devemos lembrar das ferramentas ideais para nos auxiliar em nosso ambiente. Pensar nos testes como sendo automatizados, pois são mais eficientes que qualquer teste de usuário, o qual também é importante.