Categories
Engenharia de software Refactoring

Otimização prematura

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!

Categories
Engenharia de software XP

Como produzir software “coxa”

Acabei de ler um post no blog do Phillip que me lembrou de uma história que eu queria escrever aqui.

A história que você lerá a seguir é uma dramatização do que acontece diariamente no mundo do desenvolvimento de software carinhosamente entitulada Como desenvolver software “coxa”.

Imagine uma empresa que está com necessidades de desenvolver um software. E imagine também que esta empresa (cliente) contratou uma empresa de 3 letras para fazer o trabalho.

Então, o projeto começa com a empresa contratada fazendo uma análise extensa do que será desenvolvido. Caso você não saiba, estas empresas te fazem acreditar que o RUP tem uma fase de análise antes de tudo, quando isso na verdade caracteriza um processo de desenvolvimento waterfall que é bem diferente do processo de desenvolvimento iterativo do RUP.

Depois de analisar exaustivamente tudo que precisa ser feito, eles acham que sabem tudo que o cliente precisa e com isso acham que sabem exatamente quanto tempo irá levar. Baseado nisso é estipulado um prazo de entrega do software para o cliente, assim como é estipulado um preço fixo para o trabalho.

Fechado o contrato, o projeto é iniciado. E quando começa o projeto sempre acontece a mesma coisa: a equipe de desenvolvimento começa a descobrir que certas coisas não são tão simples quanto pareciam ser. A equipe se depara com vários problemas que não haviam aparecido na fase de análise e cada vez fica mais chocada com a quantidade de coisas novas que vão surgindo. Nesse momento a equipe percebe que o projeto, que estimou-se que precisaria de 4 meses para ser desenvolvido, na verdade precisa de 8 meses para ser desenvolvido!

Então alguém surge com a brilhante idéia de contratar mais pessoas para a equipe. Afinal de contas, da mesma forma que nove grávidas conseguem parir um filho em um mês, 20 desenvolvedores conseguem fazer na metade do tempo o trabalho que 10 fariam – parece perfeito!

Mas espera aí, o preço já está combinado com o cliente desde o início. Então contratar mais pessoas é a maior furada, porque o cliente não pagará nada a mais por isso e se o custo do projeto for maior a empresa não terá lucro. Pior ainda, a empresa pode ter prejuízo! Neste momento a empresa decide comuncar ao cliente que o projeto terá que atrasar.

Quando a empresa vai dar a notícia para o cliente o cara normalmente quer matar o gerente do projeto, quer se matar, ou OS DOIS (depende do tamanho do projeto)! Afinal de contas ele pagou 50% adiantado e quer logo o retorno do seu investimento. Se o projeto ia demorar 4 meses e agora vai demorar 8, significa que todo o seu planejamento financeiro e de retorno de investimento do software foram por água a baixo. Nesse momento o cliente bate na mesa com força e diz: “se virem, eu não quero nem saber como vocês vão fazer mas eu quero o meu software na data combinada!”.

Exatamente neste momento foi parido um software “coxa”!

Vou explicar fazendo uma analogia: qualquer criança de 10 anos sabe que não existe “bom, bonito e barato”. Ou é bom, bonito e CARO; ou é RUIM, bonito e barato; ou é bom, FEIO e barato. Não tem jeito, é assim que funciona, não é possível ter tudo ao mesmo tempo.

Com software funciona exatamente da mesma forma. Só o que muda são as dimensões: qualidade, tempo e custo. Da mesma maneira que não existe nada bom, bonito e barato, não existe software “bom, desenvolvido rápido e barato”. Ou é bom, desenvolvido rápido e CARO; ou é bom, DESENVOLVIDO EM MUITO TEMPO e barato; ou é RUIM, desenvolvido rápido e barato.

No caso deste projeto repare que duas das dimensões do software não podem ser alteradas: preço (porque já foi combinado com o cliente e está em contrato) e tempo (porque a data de entrega já está estipulada). Sendo assim, como não dá para ter tudo ao mesmo tempo, a qualidade vai para o brejo. Neste momento é que vem a ordem do gerente de projeto: “gente, faz qualquer coisa aí, o importante é entregar o que foi combinado com o cliente, não importa como, faz tudo nas coxas mesmo!!”. E mais um software “coxa” será entregue.

Se eu contar os softwares “coxa” que eu já ví por aí ninguém acredita. O mais bizarro deles e que não poderia deixar de ser citado tinha o seguinte código na tela de autenticação (PHP):

if (($_REQUEST["login"]  == "admin") && ($_REQUEST["senha"]  == "1234")) {
    header("Location: index_autenticado.php");
} else {
    header("Location: index.php?mensagem=Login%20invalido");
}

No final das contas, quando o projeto é entregue, o cliente vê as telinhas e se as telinhas estiverem aparecendo e estiverem no mínimo bonitinhas ele vai dar pulos de alegria! Eventualmente até irá contratar a empresa para outro projeto ou indicar para amigos e outros projetos dentro da sua empresa. Por baixo dos panos existe esse monte de lixo, mais ou menos como um vulcão que pode entrar em erupção a qualquer momento causando efeitos devatadores! Deixa só alguém pedir para trocar a senha do sistema para ver o que vai acontecer…

Para mim é claro como água: não adianta querer prever tudo que acontecerá no projeto e pré-fixar datas e valores. É receita certa para fazer lixo. Já está mais do que provado que não funciona, porque insistir no mesmo erro?

Se você que está lendo se identificou com a história (o que não é nem um pouco difícil), sugiro fortemente que você leia sobre um modelo de contrato de desenvolvimento de software proposto pelo XP que muito me agrada: o Contrato de Escopo Negociável. O artigo é bem grande mas vale apena ler até o final! Você vai perceber que as coisas não precisam ser assim tão tristes nos projetos de desenvolvimento do software.

Categories
Comunidade TDD

Palestra sobre TDD no RioJUG

No dia 19/06 farei uma apresentação no RioJUG sobre TDD:

“Test Driven Development (Desenvolvimento Guiado por Testes) é a prática de escrever testes unitários de um software antes de escrever o código que está sendo testado. O TDD é uma prática utilizada em metodologias ágeis de desenvolvimento de software como o XP (eXtreme Programming). Esta palestra apresentará conceitos de TDD utilizando exemplos simples e de fácil entendimento. Serão apresentadas também suas vantagens, desvantagens e comparações com outros tipos de testes de software comumente utilizados.”

Para mais detalhes acesse a página do evento no site do RioJUG.

Apareçam por lá! 🙂

Categories
Fun

Flame Wars

Para quem não sabe, flame war é uma discussão entre duas ou mais pessoas onde as pessoas ou grupos de pessoas defendem idéias diferentes e normalmente opostas. Cada um dos lados fica tentando desesperadamente derrubar o outro lado com milhares de argumentos normalmente ofensivos e exagerados, até que todo mundo sai na porrada e ninguém entende mais nada. E neste momento quando tudo parece que vai ficar tranquilo cada um dos trolls já está pensando no próximo flame war…

Eu até gosto de flame wars. Na verdade eu gosto de boas discussões, tanto de assistir quanto de participar. Elas em geral são muito produtivas pois exercitam os extremos de uma idéia e você sempre acaba aprendendo coisas interessantes sobre algum assunto.

O problema é que os profissionais da nossa área têm uma forte tendência a serem religiosos extremistas com suas tecnologias preferidas! Caramba, é impressionante, todos os desenvolvedores adoram discutir o sexo dos anjos da programação. Cada um acha sempre que a linguagem que mais sabe é a melhor. Uns acham que Java serve para tudo, até para fazer um sistema operacional. Outros acham que Perl é que é perfeito, que tem a velocidade da luz (um pouco mais rápido até). Quando chega nesse ponto é que deixa de ser uma discussão interessante para virar um flame war.

O motivo deste post é que nos últimos 10 dias eu participei de pelo menos 10 flame wars sobre diversos assuntos. O único deles que realmente foi interessante/útil foi um sobre webservices SOAP x REST que começou no ActiveResource, uma classe nova do Rails que faz mapeamento objeto-serviços (semelhante ao que o ActiveRecord faz para o banco de dados). Todos os outros 9 foram pura porrada sobre religião, preferências sexuais e etc: “Windows x Linux”, “Java x Perl”, “Ruby On Rails x Perl”, “Java Magazine x Mundo Java” e por aí vai. E eu reparei que isso não acontece só comigo ou só no lugar que eu trabalho, isso sempre aconteceu nos últimos anos e em todos os lugares que eu me lembro aonde tinham profissionais de TI.

Eu acho que o motivo disto tudo está ligado a isso aqui (retirado da descrição de “Flaming” na Wikipedia):

Muitas vezes, os flamers o fazem simplesmente para estabelecerem uma posição de pseudo-superioridade ou autoridade. Em outras, os flamers desejam simplesmente ofender e irritar participantes de uma discussão ou ainda alimentar animosidades entre duas ou mais pessoas participantes da discussão, e neste caso eles são denominados trolls. Há vezes em que o flamer encontra no flaming a única maneira de resolver as diferenças entre ele e alguma outra pessoa. Na maioria das vezes, porém, os flames são mensagens enfurecidas e pouco racionais publicadas por pessoas que tem sentimentos ou ligações fortes com o assunto em questão.

No final das contas um flame war acaba sendo como uma discussão de futebol. Cada um acha o seu time infinitamente superior, o melhor do universo. O outro time só tem viados, travecos e mongolóides. A discussão começa com declarações brandas como “vai perder o jogo seu botafoguense otário”, até que no final todo mundo está saindo na porrada esfregando a cara do outro no chão. E ninguém chega a lugar nenhum. E quando acaba começa tudo denovo, sobre o mesmo assunto. E vai dar no mesmo lugar.

Então resolví escrever esse post como um convite aos meus queridos colegas desenvolvedores: POR FAVOR, chega de discussões sem fundamento (pelo menos vamos maneirar um pouco, afinal de contas ninguém é de ferro, hehehe)!

Categories
Controle de qualidade

Testes com Selenium em vários browsers

Uma empresa chamada Reality QA criou um serviço interessante. Eles testam a sua aplicação web em vários browsers e sistemas operacionais diferentes utilizando como roteiro de teste um script Selenium. Os testes rodam automaticamente nas plataformas alvo e são gerados relatórios e screenshots dos testes na medida que eles vão acontecendo.

Para ver como funciona, veja o screencast produzido pela empresa.

Como essa ferramenta é beta eles ainda não cobram pelo serviço mas já tem um link de “Buy” preparado no site.

Hoje já é possível testar em vários browsers utilizando o Selenium Core só que você tem que fazer tudo manualmente (em cada browser que irá executar o teste você tem que abrir e executar o script na mão). Talvez eles tenham usado o Selenium Remote Control e criado proxies para várias plataformas diferentes.

Achei essa idéia interessante, vou estudar uma forma de fazer alguma coisa do tipo aqui para a empresa. Depois eu conto como foi.

Categories
POG

“Gambi” Design Patterns

Acabo de fazer minha humilde contribuição ao catálogo de “Gambi Design Patterns”, os padrões de projeto utilizados pelos programadores praticantes de POG (Programação Orientada a Gambiarras).

O padrão catalogado foi o Rest Assurance Memory Allocation Pattern que consiste em alocar uma quantidade “um pouquino” maior de caracteres que uma String precisaria, só para garantir.

Vale apena dar uma olhada nos outros padrões que também são muito interessantes. Eu já ví VÁRIOS deles em prática!!! 🙂

Categories
Controle de qualidade Engenharia de software TDD

Qual é o percentual ideal de cobertura de testes?

Ontem estava tendo uma discussão com um amigo aqui do trabalho sobre cobertura de testes.

A nossa discussão começou quando eu fui mostrar para ele um teste de aceitação em Selenium que eu fiz para uma parte do sistema de gerenciamento de conteúdo da empresa.

Ele estava argumentando que acha que os testes de aceitação com Selenium não são tão interessantes porque eles são muito frágeis – alterações na interface podem quebrar os testes. Realmente isso pode acontecer. Mas se acontecer é só reescrever o teste, oras! Antes dele quebrar ele será executado várias vezes e só nisso várias horas preciosas podem ser economizadas.

Repare o seguinte: você efetivamente testará as telas do sistema navegando nele, incluindo, editando e removendo itens. Se este trabalho pode ser automatizado, porque não fazê-lo? Não é melhor gastar o seu tempo para elaborar novas táticas de testes e novos testes de outras partes do sistema ao invés de ficar navegando em todas as páginas “manualmente”?

Discussões deste tipo me fazem lembrar do manifesto Testivus, que dentre outras coisas prega que: “An imperfect test today is better than a perfect test someday” (Um teste imperfeito hoje é melhor do que um teste perfeito algum dia). Mesmo que os seus testes não sejam os melhores do mundo e que vez ou outra precisem ser corrigidos, é melhor tê-los do que não ter teste nenhum. Com o tempo a cultura de testes fica impregnada na equipe e os testes vão ficando cada vez melhores e mais numerosos.

É claro que eu não concordo que os testes possam ser um monte de lixo que não testam nada. Eu só acho que não se pode ter uma abordagem dogmática em relação aos testes. Se a sua aplicação tem 50% de cobertura de testes eu não acho isso ruim. Aliás, é BEM mais do que a maioria que existe por aí. Mesmo assim você pode (deve) testar bem mais.

Concluindo, eu particularmente gosto muito de utilizar a abordagem de desenvolvimento guiado por testes (TDD). Com TDD você tem uma cobertura de testes significativa já que os testes vão sendo escritos na medida que a aplicação é escrita. Porém se isso não puder ser feito por algum motivo, não acho correto estipular um percentual mínimo ideal de cobertura de testes. Só acho que deve-se testar muito e quanto mais, melhor.

Coincidentemente saiu ontem uma matéria no InfoQ sobre este mesmo assunto que vale apena a leitura.

Categories
Engenharia de software

Joga fora no lixo!

Acabei de ler um post bem humorado no Blog do Maurício Linhares sobre entulhos que você guarda durante toda a vida sem saber o porque.

Fiquei me sentindo meio idiota porque eu sou O CARA que guarda as coisas! Não sei porque mas eu tenho uma tendência fortíssima a me apegar as coisas que eu desenvolvo.

Vou tentar me policiar para não fazer mais isso, já que o que o Maurício falou faz sentido completamente: o que importa para você não é o software que você desenvolveu mas sim a experiência que você adquiriu e aprendizados que teve ao desenvolvê-lo.

Leitura recomendada.

Categories
Java TDD

Testes com JUnit + HSQLDB

Hoje fiz uma experiência legal no projeto em que estou trabalhando.

Estou há um tempinho bolando uma forma razoável para testar a aplicação de cabo a rabo. A única coisa que eu ainda não estava convencido totalmente sobre como fazer era testar as classes DAO ou fazer testes envolvendo elas.

Já lí em alguns lugares algumas pessoas falando que os testes não devem utilizar o banco de dados por uma série de motivos e que os DAOs sempre devem ser mocks. Até eu mesmo já cheguei a questionar se isso é realmente necessário. Depois de um tempinho com a idéia fermentando na cabeça eu penso o seguinte:

Primeiro: É interessante testar os DAOs porque você precisa garantir por exemplo que todos os campos estão sendo lidos corretamente para os objetos e que as queries funcionam. No caso de utilização de JPA/Hibernate ainda te ajuda a validar se o mapeamento objeto-relacional está correto.

Segundo: Existem alguns tipos de testes que podem ser feitos na sua aplicação. Se falarmos de teste unitário eu concordo que não deve haver utilização de banco de dados mas sim mocks para os DAOs e tudo mais que não for objeto do teste em questão. Porém para testes de integração ou aceitação é desejável que o banco de dados seja incluído no teste já que faz parte da aplicação.

Mas o problema de envolver o BD nos testes é que eles (os testes) ficam muito lentos e isso desfavorece o desenvolvimento guiado por testes, que eu não vivo sem. Se os testes demoram eles são executados menos vezes e isso não é bom. Sem contar que se os dados do banco forem modificados os testes quebram. Argh!

Eis que surge o HSQLDB. O HSQLDB é um banco de dados escrito em Java puro, tem driver JDBC que funciona direitinho e entende comandos SQL com JOINs, GROUP BYs e praticamente tudo mais que você utiliza numa aplicação que utiliza o banco de dados de forma NORMAL (normal = não utiliza aquelas tosqueiras proprietárias do BD que depois que se usa não dá mais para trocar nem a versão do bicho!).

O que eu fiz foi fazer com que os testes se conectassem num HSQLDB ao invés do banco de dados de desenvolvimento. Para melhorar, esse HSQLDB não está nem rodando em modo server em lugar nenhum. Ele é iniciando junto com os testes e roda em memória na mesma JVM que os testes rodam.

Quais foram os ganhos obtidos com este approach:

1) Minhas queries agora estão sendo testadas, assim como a criação dos meus objetos pelos DAOs.

2) Os testes estão muito rápidos, nem parece que usam banco de dados! Eu tinha criado duas suites de testes, uma que tinha testes com BD e outra sem BD. Isso nem será mais necessário agora.

3) Agora eu tenho a garantia de que os dados de teste não serão modificados e com isso os testes não quebrarão mais por este motivo. Sabendo que os dados não mudarão posso fazer testes mais completos e elaborados.

Porém também experimentei alguns pontos negativos:

1) Qualquer alteração de modelo tem que ser refletida no script de startup do HSQLDB. O script de startup é necessário para indicar quais tabelas com quais campos e dados ele criará em memória. São CREATE TABLEs com duas ou três coisinhas a mais, muda pouca coisa.

2) Em algumas aplicações que eu trabalho tem lógica da query no hint!!! Isso acontece porque lá na empresa tem um trilhão de aplicações rodando em produção no mesmo Oracle que eu rodo minha aplicação. Sendo assim se eu faço uma query ferrada eu derrubo o banco e junto com ele uma boa parte da empresa. Para evitar que isso aconteça os DBAs otimizam uma boa parte das queries que fazemos, só que as vezes a coisa fica tão dramática que os DBAs têm que fazer MAGIAS no hint para a query executar num tempo razoável. Aí eles mexem tanto no hint que no final a query depende do hint para funcionar, quando o hint deveria ser só para ela ficar mais rápida. Aí fica assim: com o hint a query retorna o resultado de um jeito e sem hint de outro! Como hint é coisa do Oracle e o HSQLDB entende como comentário, eventualmente não será possível testar uma ou outra query porque no HSQLDB o resultado será retornado sem executar a lógica contida no raio do hint!

Vou evoluir mais em cima desta idéia e na medida que as coisas forem acontecendo eu posto aqui mais comentários.

Categories
Comunidade Mercado

E dá-lhe ThoughtWorks!

Os caras da ThoughtWorks se empolgaram! Não tem nem duas semanas que lançaram o Mingle e acabo de ficar sabendo de mais um, o CruiseControl Enterprise.

Eu acho que eles vão ganhar bastante dinheiro com os dois. E espero que eles ganhem mesmo porque os dois são muito bons. Só espero que eles não parem de produzir as coisas livres legais que sempre produziram (XStream, XFire, PicoContainer, etc) para passar a vender tudo! Bom, pelo menos na enterevista que eles deram no InfoQ disseram que o produto pago irá contribuir com a comunidade também, o que é bem legal. Se continuar assim está bom.