Agendando tarefas em aplicações Rails com rufus-scheduler 1

Posted by Rodrigo Panachi on maio 31, 2009

Rufus é um conjunto de gems utilizado para Workflow e BPM. O rufus-scheduler é a gem responsável pelo agendamento e execução de tarefas (jobs). Se você programa em Java e conhece o Quartz não vai ter dificuldade em utilizá-la.

Instalação:

sudo gem install rufus-scheduler

Utilização:

require 'rubygems'
require 'rufus/scheduler'

scheduler = Rufus::Scheduler.start_new

scheduler.every '5m' do
  puts 'Executando a cada 5 minutos'
end

scheduler.schedule '0 18 * * *' do
  puts 'Executando todos os dias as 18h'
end

Simples assim! Consulte a documentação oficial ou contribua com o código.

Gerando cheat sheet para os snippets do gedit 1

Posted by Roger Leite on maio 05, 2009

Acredito que a maioria de vocês conhecem e/ou já usaram as famosas cheat sheets (tradução para “cola”?) para algo. Costumo usá-las quando quero fixar algum conceito novo ou simplesmente para consultas rápidas. Com o pai Google, é possível encontrar os mais diversos tipos: HTML, Ruby, Ruby on Rails, Shell Script… etc.

Atualmente venho praticando Ruby, sendo o gedit - “tunado” com vários plugins - o meu maior aliado. Um dos plugins que mais me ajuda é o Snippets e neste post do Cássio Marques, você encontra uma breve descrição do que é, e um link para snippets de exemplo.

Tudo isso foi só pra contar o que me levou a criar a gem gedit-snippets-tool. Com ela é possível criar cheat sheets dos seus snippets. Supondo que você tenha ruby e rubygem instalados, seu modo de uso é muito simples. Para instalar a gem execute:

sudo gem install rogerleite-gedit-snippets-tool -s http://gems.github.com

Após a instalação, para gerar um cheat sheet com todos os seus snippets, execute:

gedit-snippets-tool -cs > ~/mycheatsheet.xhtml

Caso tenha muitos snippets, e deseja criar um cheat sheet somente com Ruby e Ruby on Rails por exemplo, execute:

gedit-snippets-tool -cs ruby* > ~/mycheatsheet.xhtml
Meu cheat sheet de exemplo

Meu cheat sheet de exemplo

Levando em conta que a gem foi feita em três dias e focamos somente o necessário para lançarmos uma versão 0.x “em produção”, vamos as limitações:

  • O gedit-snippets-tool lê os snippets (arquivos XML) que estão na pasta “home”. Constatei que o gedit “limpo” logo após habilitar o plugin Snippets, guarda os snippets na pasta “/usr/share/gedit-2/plugins/snippets/”. Bom, se for este o seu caso, peço a gentileza de copiá-los para a “home” em “{home-folder}/.gnome2/gedit/snippets/”.
  • O template usado para gerar a página xhtml está bem “rústico”. O lado bom disso é que está bem fácil de alterá-lo. Vejam o código do template (via gist, leitores de RSS, sorry):

Quem tiver sugestões (inclusive de template), podem forkar o projeto ou se quiser, deixe um comentário que eu entro em contato.

Sobre o Desenvolvimento

Assim que tive a idéia, análisei o que seria necessário, e resumindo:

  • Ler os XMLs dos snippets;
  • Uma engine para gerar páginas através de “templates”;
  • Fazer uma gem executável… pois assim é mais fácil e rápido para quem quiser usá-la;

A parte do XML é fácil, pois até já fiz coisa parecida antes. A parte da engine para templates, o pai Google me guiou a uma ótima, chamada Erubis, que é uma gem e torna as coisas muito mais fáceis.

Para criar o esqueleto da gem, usei o gemhub do Diego Carrion, que facilitou muito o meu trabalho, sem contar a ajuda que me deu na hora de publicar o gemspec no github… valeu truta! Bom, o resto foram três noites programando e aprendendo a fazer a minha primeira gem. Quem quiser participar estão todos convidados a “forka-lo” no github.

jQuery DataTables, GitHub API e links da semana 2

Posted by Equipe 1up4dev on maio 04, 2009

jQuery DataTables

Nós somos fãs de jQuery pela sua simplicidade e poder de extensão através de plugins. Falando nisso, este plugin torna qualquer tabela <table/> em um “grid” ordenável, pesquisavel e paginável automagicamente.

Para usar, basta incluir o plugin na página após o jQuery e executar o script:

$(document).ready(function() {
    $("id-tabela").dataTable();
}

No site oficial é possível consultar a documentação, exemplos e a tradução para pt-br.

GitHub API, version 2

Os caras do GitHub não são fracos não… já faz um tempinho, mas antes tarde do que nunca, anunciaram em seu blog a versão 2 do GitHub API. Ela provê acesso à “Repository, User, Commit, Object and Network” e futuramente ao Gist também. Como é a primeira release e ainda estão trabalhando nela, o próprio pessoal do Github pede ajuda a “desbravadores” e que abram tickets, caso encontrem algo. Documentação você encontra em develop.github.com.

Links da semana

8 características de User Interfaces (UI) de sucesso

Nifty Generators para Ruby on Rails

JRuby on Rails no Google App Engine

Grid com ordenação e paginação animados

Guia de Ruby do Why e Autospec-notification

Posted by Equipe 1up4dev on abril 27, 2009

O comovente guia de Ruby do Why

Este livro é sensacional e demonstra exatamente o espírito do Ruby: papo de programador.

O livro é bem divertido. As tirinhas das raposas são ótimas. Várias pessoas contribuíram com a tradução para pt-br que está disponível no Github.

Leitura obrigatória. Chunky bacon!

Autospec-notification

O Autospec é um script gerado pelo RSpec que utiliza o Autotest para rodar os testes automaticamente a cada alteração no código.

Unindo o útil ao agradável, foi criado o Autospec-notification, que exibe as notificações do autospec no desktop.

Para instalar, comece pela gem ZenTest:

sudo gem install ZenTest

No linux, instale o Libnotify:

sudo apt-get install libnotify-bin

Agora instale a gem do autotest-notification:

sudo gem install carlosbrando-autotest-notification --source=http://gems.github.com

Ative o autotest-notification e rode o autospec no seu projeto:

an-install
script/autospec

O código está no Github. Escreva seus testes e divirta-se!

Agilidade é a buzzword do momento 3

Posted by Rodrigo Panachi on abril 22, 2009

Nos últimos anos o mercado de TI cresceu exponencialmente. Surgiram desde pequenas empresas especializadas em construir websites até monstruosas fábricas de software com seus contratos milionários. Algumas com orçamento limitado outras com dinheiro jorrando pelos canos. Umas com problemas por falta de organização outras com problemas burocráticos. Bons profissionais vs. equipes de sobrinhos, habilidade técnica contra enxurradas de documentos… muito fracasso, pouco sucesso.

A meta é coletar as moedas até conseguirmos uma estrela

Surgiram muitas empresas especializadas em desenvolver software ou que têm um software como produto principal. Normalmente, essas empresas se preocupam apenas em satisfazer os investidores e se esquecem dos clientes. Focam em vender e deixam a qualidade de lado. Prezam pela imagem e ignoram os problemas.

É uma triste realidade que essas empresas tenham mais executivos do que programadores. Como diz o Luli Radfahrer, executivos são aqueles seres que se vestem com um pensamento fracassado, usam uma linguagem própria sendo uma mistura de termos que só eles entendem e 20% de palavras em inglês… não vivem os problemas reais da empresa. É como se estivessem em outro mundo: Mario World!

O mundo dos executivos: nuvens sorrindo

A maioria das empresas que têm problemas com desenvolvimento de software ainda estão vivendo na década de 90. Internet ainda é uma palavra assustadora. Programador é apenas um funcionário que sabe o que significam siglas de informática e sabem mexer no computador. Mudança ainda é encarada como algo arriscado, que deve ser planejado, estudado e aprovado pelo presidente, diretoria e gestores. A palavra da vez é processo e seu fiel companheiro é prazo. A burocracia é uma amiga que garante que as coisas não fujam de controle. Nesse cenário não há como fugir do waterfall.

O maior problema do waterfall são os papéis: cada um com sua “especialidade”. Alguém determina que um infeliz funcionário vai ser responsável por “levantar requisitos”. Faz um cursinho de UML e começa a escrever uma quantidade sem fim de Casos de Uso sem ter noção alguma do que seu trabalho afeta no processo. Então a “equipe” começa a ter muito “retrabalho”, uma vez que os clientes não estão satisfeitos com o que está sendo entregue. Logo percebem que devem fazer o “levantamento” mais detalhado e passam a engessar ainda mais o processo com reuniões, assinaturas, etc. Conclusão: tempo e dinheiro desperdiçados e nenhum resultado satisfatório.

Seu trabalho é digitar xxx a cada 108 segundos

Meu trabalho é digitar 4 8 15 16 23 42 a cada 108 segundos

Falta de foco? Profissionais não qualificados? Processo falho? Não apenas isso: não há comunicação, não há troca de experiências. O waterfall favorece o aparecimento da síndrome do funcionário público: “eu sou gerente: eu córdeno, não preciso saber programar”. As decisões geralmente são tomadas por uma única pessoa. Os projetos seguem o modelo de construção civil. Os profissionais se acomodam pois não veem perspectiva, não conhecem o processo completo, não são ouvidos e por isso não são valorizados.

O foco destas empresas está longe de ser tecnologia. Se concentram em suas buzzwords, processos e reuniões e se esquecem do produto, ou seja, o software. Focam mais na solução do que no problema. Fazendo uma analogia, essas empresas são como um barco furado, onde está entrando água mas há pessoas com baldes para retirá-la e mantê-lo flutuando. Se a agua subir muito, contratam mais pessoas para operar os baldes. Enquanto isso, os executivos ficam acenando como se nada tivesse acontecendo. Quando perguntam se há algum problema, nenhum fdp infeliz tem coragem para falar que o problema é o furo no barco!

As empresas que focam em tecnologia e nos profissionais, tipo o Google ou a 37signals, estão se dando bem e mostrando que agilidade não é apenas mais um processo… é algo real e que funciona!

Agilidade é sair fazendo as coisas de qualquer jeito

Diante do cenário caótico das empresas, um grupo de profissionais organizou um movimento a fim de unificar as práticas bem sucedidas e tornar o processo de desenvolvimento mais produtivo e pragmático: o manifesto ágil. Quem freqüenta esse blog sabe que nós somos fãs e seguidores das práticas ágeis, não porque somos fanáticos e acreditamos somente em uma verdade absoluta, mas por que já sofremos muito com projetos e empresas fracassadas, vivenciamos os problemas que compartilhamos neste blog, passamos noites em claro corrigindo código escrito por maus profissionais, acumulamos horas em reuniões suficiente para tirarmos brevê, tivemos que negociar com cliente, com o chefe, fazer entrevista, contratar, gerenciar, analisar, programar, testar… nós sofremos os problemas do waterfall na pele!

O termo agilidade é bem popular atualmente: “precisamos agilizar nosso processo de desenvolvimento”. Como divulgação do manifesto ágil é algo muito positivo, pois mais pessoas podem conhecer e utilizar as práticas ágeis. Mas, como toda fama tem seu lado negativo, não seria diferente neste caso. Muitos profissionais “gafanhoto” estão utilizando esse termo como alavancagem profissional. Já tem gerente falando que RUP é ágil, arquiteto defensor de modelagem UML ágil, diagrama ER ágil, modelo de dados ágil, caso de uso ágil, cronograma ágil, etc. Ou seja, estão distorcendo totalmente o propósito e a filosofia da agilidade.

Como disse o Chapiewski, os programadores estão querendo ir direto para a sobremesa e esquecendo de comer seus vegetais. Agile é muito mais do que desenvolver iterativamente, fazer stand-up meetings e planejamentos ágeis. Não dá para ignorar todas as práticas de engenharia de software que realmente fazem com que a produção e mudanças em softwares sejam ágeis, sem contar todos os princípios e práticas que fazem uma diferença enorme.

O mercado que não é bobo já percebeu esse movimento migratório e lançou seus cursos de “Gerenciamento de projetos ágeis com MSProject”, “Desenvolvendo aplicações web com agilidade”, “Aprenda a programar com JUnit e TDD”. Não demorou muito para que uma massa de desenvolvedores colocasse o termo ágil em seus currículos. Pretensiosos demais em achar que um cursinho qualquer pode ensinar todo conceito e técnicas ágeis catalogadas por profissionais com décadas de experiência em desenvolvimento de software.

“Estou aprendendo Ruby on Rails por que o mercado está pagando bem“. do dia para a noite surgiram milhares de especialistas ágeis. O cara que programava em .NET ou Java no modelo tradicional (digitador de código), faz um cursinho rápido e de repente começa a desenvolver aplicações numa tecnologia que exige uma enorme bagagem conceitual. Faz tudo errado, pois não sabe realmente o que está fazendo, o projeto fracassa e ainda deixa a tecnologia com má fama. Isso aconteceu com PHP, ASP e está acontecendo com Rails.

Programar é difícil, não é um trabalho para qualquer aventureiro. É preciso estudar muito, se dedicar e principalmente, gostar! Não basta apenas estudar para conseguir uma certificação pois não garante nada. Deve-se viver a programação, participar de fóruns, contribuir com projetos open-source, discutir idéias, ser auto-crítico, ler muito, praticar, apreciar as boas práticas e abolir o que não presta…

Agilidade é propor soluções simples para os problemas

Agilidade é propor soluções simples para os problemas

Agilidade não é anarquia, não significa “sair fazendo as coisas de qualquer jeito”, dizer “não” para documentação, etc. É uma mudança de atitude, uma nova maneira de enfrentar os problemas e propor soluções simples e práticas, é ter foco, é saber fazer mais com menos, é automatizar tarefas, é estar comprometido… agilidade é atitude.

Contratamos uma consultoria para implantar Scrum

Scrum é a metodologia da moda. Assim que começou a se popularizar entre a comunidade de desenvolvedores, não demorou muito para o que vários sites e blogs se dedicassem exclusivamente na sua divulgação, apresentando benefícios, artigos, guias, exemplos, certificados para imprimir e pendurar em uma moldura na parede, etc. Logo surgiram as consultorias especializadas em adestramento treinamento e implantação de Scrum nas empresas. Um pouco de política aqui e influência ali até que a INFO Magazine publicasse uma matéria dizendo sua empresa deveria usar Scrum como solução para todos os problemas.

Mais uma vez, a falta de foco e maturidade das empresas distorcem tudo. Muitas empresas “compraram” o Scrum como a solução pronta. Bastar treinar os funcionários, comprar blocos de post-it e tudo passa a funcionar bem e gerar lucro. Pagam um curso de “gerenciamento de projetos com Scrum” para os gerentes. Depois apostam todos as fichas em um projeto “piloto”. Fazem tudo que manda o manual: reuniões diárias, planing-pocker, quadro com post-its, etc. E o projeto… fracassa!

Queimando dinheiro

Queimando dinheiro

Então quer dizer que Scrum não funciona? Foi dinheiro desperdiçado? Tanto esforço para nada? Neste caso, devo dizer que sim! Se esqueceram do processo anterior falho, funcionários pouco qualificados e dos líderes sem foco. Escolheram aqueles funcionários mais “experientes” para serem o Scrum Master. Sim, aqueles mesmos que só sabiam escrever casos de uso e diagramas UML. Se esqueceram dos valores, dos princípios, da atitude, do relacionamento com o cliente. O pensamento não mudou, o foco ainda era no processo. Depois de tanto esforço, só deram outro nome o waterfall. Não demorou muito e surgiram os papéis, artefatos, documentos… ou seja, a empresa continua cometendo os mesmos erros!

Não importa a tecnologia ou processo se não souber usá-lo corretamente! E definitivamente Scrum não pode ser encarado como mais um processo bonitinho, com seus papéis, artefatos, bla bla bla. Um processo de software que funciona é aquele onde a equipe está realmente comprometida e tem experiência acumulada para enfrentar e resolver problemas ao longo do desenvolvimento da aplicação. O processo, ou metodologia, será meramente um nome para as práticas que a equipe conhece e utiliza naturalmente.

Resumo

Não há ferramenta, metodologia ou processo que substitua a atitude e experiência de um verdadeiro desenvolvedor ágil. Estude, pratique, esteja comprometido, estude denovo, questione-se, estude novamente. Revise seu código, estude mais um pouco, e principalmente, tenha atitude! Agilidade não é metodologia, é atitude!

Remarkable, jqGrid no Rails, Heroku e Github issues

Posted by Equipe 1up4dev on abril 20, 2009

Este é o primeiro post que publicaremos semanalmente reunindo novidades sobre desenvolvimento, artigos, notícias e temas variados sobre Rails.

Remarkable 3.0

Foi lançada a nova versão do Remarkable, um framework para testes com RSpec. Dentre as novidades, estão:

  • I18n, possibilitando gerar o output das specs no seu idioma favorito fluente
  • Pending Macros, facilitando o agrupamento das specs pendentes
  • Macro stubs e mais opções de Matchers, simplificando testes com mocks

Para instalar basta um sudo gem install remarkable_rails

Saiba mais no site do Carlos Brando, lendo a documentação ou espiando o código no Github.

jqGrid no Rails

jQuery é um dos frameworks Javascript mais populares do mercado. O que esse cara fez foi juntar o jqGrid, que é um plugin muito bom para trabalhar com grids, num plugin para Rails, facilitando sua utilização.

Veja aqui um guia de utilização do plugin, a aplicação de exemplo ou confira o código no Github.

Heroku

Apesar da simplicidade do Business Bingo Generator, houve muitas “manhas” aprendidas no seu desenvolvimento. O Heroku foi uma delas, onde pudemos publicar rapidamente a aplicação. Se você quer hospedar um projeto simples feito em Rails, nós o recomendamos. O seu uso é muito simples e a incrível idéia de usar o git como interface para deploy é realmente sensacional. Basta instalar o client do Heroku, dar um “git push” e pronto: a aplicação está no ar!

Github Issue Tracker

Nova funcionalidade no GitHub para facilitar nossas vidas, permitindo informar os “bugs” nos projetos. No link acima, contém o vídeo “Introduction to GitHub Issues” para mais detalhes.

Caso já use um Issue Tracker para o seu projeto no github, você pode desabilitá-lo na seção do Features na aba Admin.

Business Bingo Generator 3

Posted by Roger Leite on abril 13, 2009

Para quem tem algum tempo de internet, é fácil notar como as piadas se repetem, ou melhor, assim como olimpíadas ou copa do mundo, re-aparecem a cada quatro anos por exemplo. Não foi diferente com a piada que recebi (novamente) a pouco tempo, o Business Bingo. O que torna a piada muito divertida é o seu alto teor sarcástico e real, foi quando pensei, porque não imprimir esta cartela e realmente testar! Foi assim que surgiu a idéia de fazer um gerador de cartelas para o Business Bingo! :D

idéia

Business Bingo! Generator

A idéia deste post, além de ajudar a divulgar o site, é ter um local central para comentários, sugestões, reclamações e elogios para o Business Bingo Generator.

Curiosidade

  • O Business Bingo, também conhecido como Buzzword Bingo, ganhou notoridade em 1994, com uma tirinha publicada do Dilbert.
  • Um dos “grandes” eventos “documentados”, foi em 1996, que alunos do MIT o usaram no discurso do vice-presidente dos EUA, Al-Gore.

Uma nota rápida a desenvolvedores

A primeira versão foi desenvolvida em dois dias, isso mesmo, dois dias e já estava em produção. Eu e o Rodrigo Panachi resolvemos implementar a idéia do “generator” para aprender na prática como funciona o Ruby on Rails. Num post futuro irei colocar mais detalhes técnicos, que apesar de ser uma aplicação muito pequena, podemos tirar proveito de grandes aulas. Para quem quiser contribuir, o Business Bingo Generator está no GitHub.

TPW - Testando sistemas legados: classes Utils 2

Posted by Rodrigo Panachi on março 03, 2009

Aproveitando o gancho do post anterior sobre manipulação de dependências, decidi dedicar um post apenas sobre este tema, pois acredito ser de grande ajuda para todos desenvolvedores que precisam manter código legado.

Em projetos legados é comum encontrarmos classes Util (aka Helpers) espalhadas por todo o código, fazendo desde coisas simples como formatar datas ou números, até coisas mágicas como cache de objetos, operações com reflection, escrita de logs, etc. Mesmo que tenham sua “utilidade”, são um terror quando falamos de testes! Além de ser um forte indício de um design fraco, as chamadas a seus métodos, geralmente estáticos, geram dependências nas classes que a utilizam.

Este é a estrutura comum (bem simplificada) de uma classe Util com métodos estáticos:

public class MagicUtil {
    public static String getConstanteSecreta() {
        return "VALOR_SECRETO_AMBIENTE";
    }
}

Neste caso, uma boa estratégia para os testes seria encapsular a chamada da classe Util em um método protected, para que seja sobrescrito na classe de teste, assumindo o comportamento desejado. Porém, se a classe Util for largamente referenciada no projeto (o que é comum) seria preciso refatorar todas a classes que a utilizam para escrever um teste completo.

A estratégia proposta é refatorar a classe Util, aplicando o padrão Singleton e transformando os métodos estáticos em métodos de instância, porém mantendo as assinaturas estáticas, que devem referenciar os métodos da instância. Uma vez que a Util pode ser instanciada (mesmo que internamente), é possível manipular seu comportamento através da injeção de um objeto Mock, por exemplo:

public class MagicUtil {
    private static MagicUtil instance = new MagicUtil();
    protected static MagicUtil getInstance() {
        return instance;
    }
    protected static void setInstance(MagicUtil obj) {
        instance = obj;
    }
    public String getConstanteSecretaInstancia() {
        return "VALOR_SECRETO_AMBIENTE";
    }
    public static String getConstanteSecreta() {
        return getInstance().getConstanteSecretaInstancia();
    }
}

Assim, a Util continua com o mesmo comportamento e seu contrato foi mantido. Agora, no seu teste, basta escrever o mock (estendendo a classe e sobrescrevendo os métodos) e injetá-lo na instância interna da Util:

public class ClasseTest {
    @Test
    public void testaMetodoDependenteDeMagicUtil() {
        new MagicUtil() {
            {
                setInstance(this);
            }
            public String getConstanteSecretaInstancia() {
                return "MEU_VALOR_MOCK";
            }
        };
        Assert.assertEquals("MEU_VALOR_MOCK", MagicUtil.getConstanteSecreta());
    }
}

Neste caso a classe anônima (que estende a Util) passa sua própria instância (this) para o método protegido setInstance(). Note que a chamada do método (estático) da Util continua igual ao da classe original, sem o refactoring.

Nos projetos que preciso manter, esta estratégia tem sido muito útil para resolver os problemas das “teias” de Utils. Porém é um recurso paliativo e não deve ser utilizado como o “padrão”. O ideal é sempre evitar classes Utils, lembrando que uma classe deve sempre ter comportamentos bem definidos e o nome já deve indicar sua responsabilidade.

TPW - Testando sistemas legados: manipulando dependências 3

Posted by Rodrigo Panachi on fevereiro 19, 2009

Pela definição de Michael Feather, código legado é código sem testes! Não importa se o código foi escrito semana passada ou alguns anos atrás. Qualquer manutenção será de difícil entendimento por outra pessoa e não haverá garantias de seu funcionamento. Uma vez que não há “controle”, é mais difícil rastrear as alterações; pior do que uma nova funcionalidade que não funciona, é uma funcionalidade antiga que começa a falhar. Este é um risco que um desenvolvedor não pode correr!

Não altere código legado até que seja possível testá-lo

Um dos problemas mais comuns em sistemas legados é a interdependência de classes, ou seja, o alto acoplamento, que sempre está ligado com a baixa coesão. Se estes termos são difíceis de entender, pense em acoplamento como sendo o grau com que as classes referenciam umas as outras e coesão o quanto uma classe está focada em realizar suas responsabilidades.

Para que seja possível testar o comportamento de uma classe “acoplada”, o comportamento de suas dependências precisa ser simulado. Isto normalmente é feito através de objetos falsos, ou mocks, que são injetados na instância da classe em questão. Este padrão é conhecido como Inversão de Controle e Injeção de dependência, onde o controle sobre as dependências da classe são delegados à outro objeto, ou normalmente um container de objetos, responsável por injetar as dependências nas instâncias das classes. Simples, não?! Mas isso será detalhado em outro post…

Voltando para os testes, no post anterior começamos a organizar o projeto automatizando o build e centralizando a execução dos testes para evitar que fiquem “soltos” pelo código. Agora vamos nos concentrar em escrever os casos de teste, refatorando o necessário para lidar com as dependências das classes.

Partindo da premissa que o projeto não possuí nenhum framework de inversão de controle, utilizaremos um certo “padrão” que permite manipular as dependências de uma classe por meio de herança, sem alterar seu comportamento original. A idéia é resolver as dependências da classe através de getters protegidos, que podem ser sobrescritos em uma classe filha no momento do teste. Isso permite que, na classe estendida, o método sobrescrito retorne um objeto mock, por exemplo, com o comportamento esperado para o teste.

Vamos tomar como exemplo, uma classe simples com algumas dependências e responsável por encapsular algumas regras de negócio referentes à Estoque.

public class EstoqueLogic {
    public boolean verificaDisponibilidade(Produto produto, Integer quantidade) {
        EstoqueDAO dao = new EstoqueDAO();
        Estoque estoque = dao.localizaProduto(produto.getCodigo());
        return estoque.getQuantidade() >= quantidade;
    }
}

Da forma como esta classe foi escrita, é impossível testar a regra de disponibilidade independentemente, pois depende do objeto EstoqueDAO para localizar as informações necessárias para o método. Mas com um pequeno refactoring, a responsabilidade de resolver a dependência EstoqueDAO passa a ser responsabilidade da própria classe Estoque:

public class EstoqueLogic {
    public boolean verificaDisponibilidade(Produto produto, Integer quantidade) {
        EstoqueDAO dao = getEstoqueDAO();
        Estoque estoque = dao.localizaProduto(produto.getCodigo());
        return estoque.getQuantidade() >= quantidade;
    }
    protected EstoqueDAO getEstoqueDAO() {
        return new EstoqueDAO();
    }
}

Desta forma, é possível “injetar” um objeto que simule a dependência do EstoqueDAO estendendo a classe e sobrescrevendo o método getEstoqueDAO() para retornar a instância desejada. O teste ficaria mais ou menos assim:

public class EstoqueLogicTest {

    public void testVerificandoDisponibilidadeDeUmProduto() {

        //Criando o objeto EstoqueDAO mock, simulando o comportamento desejado
        final EstoqueDAO estoqueDAOMock = new EstoqueDAO() {
            @Override
            public Estoque localizaProduto(String codigo) {
                Produto produto = new Produto();
                produto.setCodigo(codigo);
                Estoque estoque = new Estoque();
                estoque.setProduto(produto);
                estoque.setQuantidade(5);
                return estoque;
            }
        };

        //Sobrescrevendo o método getEstoqueDAO para retornar o Mock
        EstoqueLogic logic = new EstoqueLogic() {
            @Override
            protected EstoqueDAO getEstoqueDAO() {
                return estoqueDAOMock;
            }
        };

        //Definindo o teste e executando
        Produto produto = new Produto();
        produto.setCodigo("123456");        

        boolean estaDisponivel = logic.verificaDisponibilidade(produto, 10);
        assertTrue(estaDisponivel);

        boolean naoEstaDisponivel = logic.verificaDisponibilidade(produto, 2);
        assertTrue(naoEstaDisponivel);
    }
}

O método getEstoqueDAO() da classe EstoqueLogic foi sobrescrito para retornar o objeto estoqueDAOMock com as informações necessárias para o teste, ou seja, o comportamento das dependências foi simulado, possibilitando que o teste ficasse concentrado apenas da classe Estoque.

Elimine as dependências e teste onde os bugs estão!

Este padrão fornece apenas uma maneira de lidar com as dependências das classes para escrever testes. A dica aqui é manter o foco: defina apenas testes para as funcionalidades que estiver alterando e que exercitem pontos críticos e/ou regras de negócio. Então, refatore apenas as classes necessárias para simular e validar o fluxo destes testes, nem que seja apenas seus “contratos“. Não há necessidade de escrever testes muito granulares nem alterar todas as classes de um sistema legado.

No caso de classes com muitas dependências, o melhor é refatorá-la, separar as responsabilidades e testá-las individualmente. Para classes com dependências de Utils e/ou muitas chamadas à métodos estáticos, uma estratégia parecida pode ser utilizada. Mas estes são assuntos para os próximos posts. Acompanhem!

TPW - Testando sistemas legados: automatizando o build 2

Posted by Rodrigo Panachi on fevereiro 11, 2009

Imagine o cenário: você caiu de para-quedas naquele projeto que todo mundo na empresa fez gambiarra deu manutenção e agora precisa implementar uma nova funcionalidade. Mesmo que tenha alguma documentação, vai ser inútil neste caso. Então você começa a vasculhar o código e encontra dezenas de classes com nomes parecidos, vários arquivos XML’s dos inúmeros frameworks utilizados anteriormente, TO’s, VO’s, Actions, Utils… ou seja, um lugar cheio de janelas quebradas.

O mais fácil neste caso seria fazer seu trabalho, quebrando mais algumas janelas caso necessário, e cair fora o quanto antes. Mas você, desenvolvedor ágil, sabe que além de ser falta de profissionalismo, você corre o risco de cair novamente no mesmo projeto. Então aproveite a oportunidade para fazer uma pequena faxina e preparar o projeto para escrever os testes das novas funcionalidades que irá desenvolver, garantido assim a qualidade, pelo menos, do seu trabalho.

Durante minha carreira fui obrigado tive a oportunidade de dar manutenção em diversos projetos “frankenstein” de onde adquiri certa experiência para poder “organizar a casa” e trabalhar decentemente no código. É claro que não estou falando em escrever testes para o projeto inteiro, mas pelo menos garantir a qualidade do código que desenvolvi ou irei desenvolver.

Há um certo padrão que todo software de qualidade deve seguir. Além dos padrões e boas práticas como organização do código em pacotes vs. responsabilidade, uma coisa essencial para o projeto é sua construção, ou seja, a forma que o software é “entregue”. Acredito que este seja o primeiro passo para começar a organizar a bagunça de um projeto.

A construção do projeto deve ser automática e desempenhada por uma ferramenta de build como o Ant ou Maven, com tarefas (tasks) e objetivos bem definidos. Normalmente, um build do projeto deve:

  1. Preparar o código e dependências
  2. Compilar os arquivos fontes
  3. Executar os testes
  4. Empacotar a distribuição

No exemplo abaixo usarei o Ant, que é a ferramenta de build (para Java) mais popular do mercado e muito simples de utilizar. O importante neste processo é ser pragmático: não perca o foco! Você poderia (e futuramente deveria) utilizar o Maven, mas adequá-lo a um sistema legado não é tão simples quanto parece.

Tendo os objetivos do build definidos, basta escrever o script do Ant. Isso deve ser feito no arquivo build.xml, no root do projeto. As tarefas são definidas pelas tags <target> e podem ser dependentes para garantir a sequencia de execução. Em cada target são definidas as ações executadas, como rodar o compilador (javac), copiar um arquivo, rodar os testes, etc. Uma vez que as tarefas estão configuradas, basta executar o build pelo próprio IDE ou linha de comando.

<project name="frank" default="package">
    <path id="classpath">
        <pathelement location="build/bin"/>
        <fileset dir="src">
            <include name="*.java"/>
        </fileset>
        <fileset dir="lib">
            <include name="*.jar"/>
        </fileset>
    </path>
    <target name="clean">
         <delete dir="build"/>
          <mkdir dir="build"/>
    </target>
    <target name="compile" depends="clean">
        <javac srcdir="src" destdir="build">
            <classpath refid="classpath"/>
        </javac>
    </target>
    <target name="test" depends="compile">
        <junit>
            <classpath refid="classpath"/>
            <batchtest>
                <fileset dir="build" includes="*Test"/>
            </batchtest>
        </junit>
    </target>
    <target name="package" depends="compile, test">
        <war destfile="frank.war" webxml="web/WEB-INF/web.xml">
        <classes dir="build"/>
    </target>
</project>

Neste script estão definidas as tarefas necessárias para executar um build, conforme citei anteriormente. Por enquanto isto será o mínimo necessário para dar suporte as próximas etapas da sua missão. Mesmo que o projeto já tenha um build em Ant aproveite para revisá-lo. Tarefas bem simples e bem definidas são mais fáceis de entender e manter.

Com o build implementado, você não terá mais que se preocupar com o empacotamento do projeto. Agora comece a direcionar seus esforços para escrever os testes. Deixe que o Ant se encarregará de executá-los para você.

No próximo post vou apresentar alguns padrões e práticas de refactoring utilizados para possibilitar escrever testes que dependem de classes legadas do projeto.