18.05.2013 Views

A Relação Entre Desenvolvimento Orientado a Testes e Qualidade ...

A Relação Entre Desenvolvimento Orientado a Testes e Qualidade ...

A Relação Entre Desenvolvimento Orientado a Testes e Qualidade ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

A <strong>Relação</strong> <strong>Entre</strong> <strong>Desenvolvimento</strong> <strong>Orientado</strong> a <strong>Testes</strong><br />

e <strong>Qualidade</strong> de Software<br />

Cássio L. Ribeiro 1<br />

1 Instituto de Informática – Pontifícia Universidade Católica de Goiás (PUC Goiás)<br />

Goiânia – GO – Brasil<br />

cassio.landim@gmail.com<br />

Abstract. This paper shows how the consequences of the use of test-driven development<br />

affect the quality of software. It lists some situations that negatively<br />

affect the quality of software, such as the lack of unit testing and presence of<br />

disorganized code. It demonstrates how the use of test-driven development mitigates<br />

or eliminates the occurrence of these situations. Finally, it highlights other<br />

important quality factors that the test-driven development does not resolve properly.<br />

Resumo. O presente artigo evidencia de que maneira as consequências do emprego<br />

do desenvolvimento orientado a testes afetam a qualidade de um software.<br />

São listadas algumas situações que afetam negativamente a qualidade de um<br />

software, como a ausência de testes unitários e a presença de código desorganizado.<br />

Demonstramos como o emprego do desenvolvimento orientado a testes<br />

ameniza ou elimina a ocorrência dessas situações. Ao final, evidencia outros<br />

fatores importantes para a qualidade, que o desenvolvimento orientado a testes<br />

deixa a desejar.<br />

1. Introdução<br />

A natureza ubíqua da computação moderna, software e infraestrutura de informação e,<br />

ainda, a demanda crescente por automação e conveniência pela sociedade moderna tem<br />

gerado constante aumento de tamanho e complexidade dos sistemas de software modernos.<br />

Este incremento em tamanho e complexidade acaba por causar consequências nãointencionais<br />

em termos de gerar problemas de qualidade [Tian 2005].<br />

A alta complexidade e o amplo escopo dificultam a prevenção ou eliminação de<br />

problemas de software e seus impactos negativos relacionados; consequentemente, várias<br />

atividades de garantia da qualidade são realizadas para prevenir e/ou eliminar certas classes<br />

de problemas, ou ainda, para reduzir a probabilidade ou severidade de tais impactos<br />

quando não se pode evitá-los [Tian 2005].<br />

As metodologias ágeis emergiram da necessidade de se minimizar os riscos do<br />

desenvolvimento de softwares. Essas metodologias evoluíram como parte de uma reação<br />

contrária aos processos de desenvolvimento utilizados na época, caracterizados como<br />

“pesados”, burocráticos, micro-gerenciados e com uma alta tendência a se produzir documentos<br />

formais [Langr 2005].<br />

Como o desenvolvimento orientado a testes (Test-Driven Development - TDD) é<br />

uma prática fundamental da Programação Extrema (eXtreme Programming - XP), que está


começando a ganhar uma ampla aceitação entre as entidades desenvolvedoras de software,<br />

este estudo visa evidenciar de que maneira o emprego do TDD afeta a qualidade de um<br />

software.<br />

2. Conceitos de <strong>Qualidade</strong> de Software e TDD<br />

2.1. <strong>Qualidade</strong> de Software<br />

[Tian 2005] coloca a qualidade sob a perspectiva das expectativas dos usuários de software.<br />

Em geral, o que as pessoas esperam como qualidade em um sistema de software<br />

é que eles façam o que foram programados para fazer. Em outras palavras, eles devem<br />

fazer a coisa certa, ou seja, eles devem executar suas tarefas específicas corretamente ou<br />

satisfatoriamente.<br />

Comportamentos inesperados se manifestando na forma de defeitos, podem afetar<br />

profundamente a qualidade de um software, porém, este não é o único fator que determina<br />

a qualidade. Segundo [Friedman 2009], as metodologias ágeis tratam o processo<br />

de incremento da qualidade como um exercício de “eliminação do desperdício” onde o<br />

conceito de “desperdício” assume o mesmo significado no contexto da manufatura lean<br />

1 [James P. Womack 1990], onde um produto de alta qualidade é aquele que previne o<br />

desperdício do esforço investido pelo usuário no processo de produzir algo de valor.<br />

[Friedman 2009] identifica três fatores principais de desperdício que reduzem a<br />

qualidade de um software. O primeiro e mais comum são os defeitos. Estes podem ser<br />

categorizados como ocorrências onde o sistema se comporta de forma inesperada. Enquanto<br />

o desenvolvedor espera que o sistema se comporte de certa maneira, o comportamento<br />

exibido é diferente devido a defeitos inseridos na fase de codificação. O problema<br />

é que quando um defeito afeta o usuário, em casos menos graves, pode forçar o usuário<br />

a repetir alguma ação, enquanto que em casos extremos pode causar uma perda substancial<br />

de dados que irá requerer um esforço significativo para serem reproduzidos (quando<br />

possível).<br />

O segundo fator está ligado a problemas de usabilidade, onde um produto de difícil<br />

uso causa um desperdício de esforço. Em casos extremos, os usuários fazem uso<br />

de caminhos alternativos para atingirem seus objetivos; entretanto, em vários casos, os<br />

usuários empregam a forma incorreta de execução ao invés de perceber que a qualidade<br />

atual do sistema é insuficiente para atender seus propósitos.<br />

O terceiro fator, funcionalidades do sistema que não são utilizadas, também representam<br />

um fator de desperdício. Além de inúteis, retardam e dificultam o uso do sistema.<br />

Esta é a forma de desperdício que mais despende esforços para ser localizada e eliminada.<br />

2.1.1. Verificação versus Validação<br />

Verificação é provar que o produto atende corretamente os requisitos especificados em<br />

atividades prévias durante o ciclo de vida de desenvolvimento, já a validação checa que o<br />

1 O termo lean foi cunhado ao final da década de 80 em um projeto de pesquisa do Massachusetts Institute<br />

of Technology (MIT) sobre a indústria automobilística mundial. A pesquisa revelou que a Toyota havia<br />

desenvolvido um novo e superior paradigma de gestão nas principais dimensões dos negócios (manufatura,<br />

desenvolvimento de produtos e relacionamento com os clientes e fornecedores).


sistema atende os requisitos do cliente ao final do ciclo de vida. Tradicionalmente, teste<br />

de software tem sido considerado um processo de validação, isto é, uma fase do ciclo de<br />

vida [Lewis 2004].<br />

2.1.2. <strong>Qualidade</strong> Externa e Interna<br />

<strong>Qualidade</strong> externa é a qualidade medida pelo cliente, e qualidade interna é a qualidade<br />

medida pelas pessoas que possuem acesso ao código, como é o caso dos programadores<br />

e arquitetos.<br />

As metodologias ágeis pregam que a qualidade interna de um software não é negociável,<br />

ela deve ser fixada como ótima durante todo o ciclo de vida do software. Algumas<br />

equipes, na esperança de reduzir o prazo de entrega, sacrificam temporariamente<br />

a qualidade interna na esperança de que a qualidade externa não sofrerá um grande impacto.<br />

Esta estratégia é muito tentadora em um cenário em curto prazo. Porém, eventualmente<br />

problemas de qualidade interna o alcançarão e tornarão aquele software proibitivamente<br />

caro de manter ou mesmo incapaz de alcançar um nível competitível de qualidade<br />

externa [Beck 1999]. Este fenômeno é conhecido como débito tecnológico. Segundo<br />

[Friedman 2009], tentar trocar a qualidade por velocidade é uma das estratégias mais errôneas<br />

existentes.<br />

2.2. <strong>Testes</strong> Unitários<br />

De acordo com [Lewis 2004], teste unitário é a escala mais “micro” de testes para testar<br />

funções particulares ou módulos de códigos. Tipicamente são feitos pelo programador e<br />

não por testadores, já que requerem um conhecimento detalhado do código e do design<br />

interno do software. Nem sempre são fáceis de se implementar a não ser que a aplicação<br />

tenha uma arquitetura muito bem desenhada com código organizado.<br />

[Bellware 2009] acredita que quando testes são escritos após o código de produção<br />

já estar pronto, na realidade o que se está fazendo é um tipo de engenharia reversa, que é<br />

uma forma de engenharia de que exige uma grande quantidade de esforço. Exige muito<br />

esforço porque ao se escrever os testes neste momento, o programador precisará ler todo<br />

o código, entender o que ele faz e adivinhar como escrever um teste para este código.<br />

Os testes produzidos desta maneira acabarão, provavelmente, não servindo para cobrir o<br />

mínimo necessário dos caminhos alternativos de execução do código.<br />

2.3. <strong>Desenvolvimento</strong> <strong>Orientado</strong> a <strong>Testes</strong><br />

As metodologias ágeis já se tornaram populares na área de desenvolvimento de software.<br />

A cada dia, mais empresas as adotam para amenizar problemas de qualidade e de entrega<br />

de produtos que agreguem o valor real aos seus clientes.<br />

Algumas metodologias ágeis como Scrum tem foco em práticas gerenciais e organizacionais,<br />

enquanto XP tem foco maior em práticas de programação. O TDD é uma<br />

das práticas que fazem parte do núcleo do XP [Beck 1999] que entra em cena durante as<br />

fases de desenho e codificação de um software.<br />

XP é uma metodologia ágil e leve para equipes de desenvolvimento de software<br />

de tamanho pequeno à médio que lidam com requisitos vagos ou que mudam rapidamente


[Beck 1999]. XP procura melhorar um projeto de software através da comunicação, simplicidade,<br />

feedback, respeito e coragem. Dá ênfase no trabalho em equipe, permitindo que<br />

os desenvolvedores respondam com confiança às mudanças de requisitos dos clientes, até<br />

mesmo tardiamente no ciclo de vida do projeto.<br />

Scrum é um processo ágil para o desenvolvimento de projetos, sendo mais adequado<br />

para projetos onde os requisitos estão mudando ou emergindo rapidamente. É mais<br />

focado nas pessoas e na forma como elas deverão interagir entre si para atingir um objetivo<br />

comum.<br />

[Schwaber 2004] afirma que o Scrum baseia todas as suas práticas em uma estrutura<br />

de processo incremental e iterativo. Esta estrutura é formada por iterações de<br />

atividades de desenvolvimento que ocorrem uma após a outra, sendo que a saída de cada<br />

iteração é um incremento do produto. Dentro desta iteração ocorrem várias iterações mais<br />

curtas (inspeções diárias), onde os indivíduos membros do time se encontram para inspecionar<br />

as atividades dos outros membros e fazerem as adaptações necessárias. Uma lista<br />

de requisitos guia a iteração. Este ciclo se repete até que o projeto termine.<br />

Ao início de cada iteração, o time analisa o que deve ser feito. Ele então escolhe o<br />

que acredita que possa se tornar um incremento de funcionalidade potencialmente entregável<br />

ao final da iteração. O time é deixado a sós para fazer seu melhor esforço pelo resto<br />

da iteração. Ao final da iteração, o time apresenta o incremento de funcionalidade que<br />

construiu para que os patrocinadores do projeto possam inspecioná-lo e fazer ajustes para<br />

as próximas iterações do projeto. O processo criativo durante as iterações é o coração da<br />

produtividade do Scrum.<br />

Já o TDD é uma prática que visa aumentar a velocidade da entrega de produtos<br />

através da simplificação das atividades de desenho de software. [Koskela 2008] resume a<br />

filosofia do TDD em uma frase – somente escreva código para fazer um teste falho passar.<br />

[Astels 2003] define o TDD como sendo um estilo de desenvolvimento onde:<br />

• Uma suíte exaustiva de testes de programadores é mantida;<br />

• Nenhum código entra em produção a não ser que tenha testes associados;<br />

• Os testes são escritos antes;<br />

• Os testes determinam que código precise ser escrito.<br />

2.3.1. Ciclo Teste-Codificação-Refatoração<br />

TDD é uma técnica de desenho e desenvolvimento que nos ajuda a construir um sistema<br />

de forma incremental, com a consciência de que nunca nos afastamos de uma baseline<br />

funcional e entregável. O ciclo Teste-Codificação-Refatoração é quem dita o ritmo do<br />

desenvolvimento através de pequenos e controlados passos. A sequência clássica que nos<br />

foi ensinada, onde primeiramente produzimos o desenho, implementamos o desenho, e<br />

só então testamos o software em busca dos defeitos, é totalmente invertida quando comparada<br />

ao ciclo Teste-Codificação-Refatoração.<br />

Primeiramente escrevemos o teste, depois escrevemos o código para fazer este<br />

teste passar e então passamos para a fase de desenho. Esta fase de desenho é diferente da<br />

fase de desenho tradicional. No TDD ela é chamada de refatoração, onde o desenho atual<br />

do código é transformado em um desenho melhor.


O ciclo Teste-Codificação-Refatoração também pode ser chamado de ciclo<br />

Vermelho-Verde-Refatoração [Astels 2003]. O vermelho simboliza a fase inicial do ciclo<br />

TDD onde o teste escrito falha. Ele falha porque o sistema não está funcional; ele<br />

não possui as funcionalidades que desejamos que ele tenha. Em alguns ambientes de<br />

desenvolvimento, essa falha é evidenciada através da exibição de uma barra vermelha.<br />

Na segunda fase implementamos as funcionalidades que faltavam para fazer todos<br />

os testes passarem, ou seja, os testes que já existiam e o novo teste recém-introduzido.<br />

Neste momento, a barra visual deve se tornar verde. Somente se passa para a próxima<br />

etapa quando nenhum teste estiver falho.<br />

Na última parte do ciclo é feita a refatoração. Refinamos o desenho do código<br />

sem alterarmos seu comportamento externo, mantendo todos os testes passando e a com<br />

a barra visual exibindo a cor verde.<br />

3. A <strong>Relação</strong> entre TDD e <strong>Qualidade</strong><br />

<strong>Qualidade</strong> não pode ser alcançada através da avaliação de um produto já feito. O objetivo,<br />

portanto, é prevenir defeitos de qualidade ou deficiências em primeiro lugar, tornando os<br />

produtos avaliáveis através de medidas de garantia de qualidade [Lewis 2004].<br />

[Beck 1999] cita alguns exemplos de riscos relacionados ao desenvolvimento de<br />

software. Dos riscos citados, dois estão diretamente ligados a qualidade de software e<br />

podem ser tratados através da utilização de TDD:<br />

• Taxa de defeitos – o software é colocado em produção mas a taxa de defeitos é tão<br />

alta que ele acaba não sendo utilizado. TDD eleva a validação de um software a<br />

um patamar superior, testando-o função por função;<br />

• Deterioração do sistema – o software é colocado em produção com sucesso, porém<br />

após algum tempo o custo de se fazer modificações ou a taxa de defeitos aumenta<br />

tanto que o sistema precisa ser substituído. TDD mantém o programador focado<br />

na solução, de forma que o software não fica carregado de códigos desnecessários,<br />

duplicados ou de difícil manutenção, impedindo a deterioração do sistema.<br />

Nesta mesma obra, [Beck 1999] elaborou três frases de impacto, que servem como<br />

um ponto de partida para entendermos como o TDD afeta a qualidade de um software:<br />

• Toda vez que alguém toma uma decisão e não a testa, existe uma grande probabilidade<br />

de que esta decisão esteja errada;<br />

• Funcionalidades de software que não podem ser demonstradas através de testes<br />

automatizados simplesmente não existem;<br />

• <strong>Testes</strong> nos dão à chance de pensar sobre o que queremos, independente da forma<br />

como a solução será implementada.<br />

Ao utilizar TDD, devemos escrever testes para cada solução implementada. Dessa<br />

forma, diminuímos a probabilidade de tomarmos uma decisão errada. Ao mesmo tempo,<br />

temos a oportunidade de experimentar várias implementações diferentes para o mesmo<br />

problema e escolher aquela mais limpa, elegante e que apresente o melhor desempenho.<br />

Na época em que [Beck 2002] publicou sua obra, afirmou que ainda não haviam<br />

estudos que demonstrassem científicamente as diferenças na qualidade, produtividade ou<br />

diversão entre a utilização de TDD e quaisquer outras alternativas. Atualmente já existem


publicados alguns estudos objetivos sobre o impacto da utilização de TDD com relação à<br />

qualidade e produtividade, frente à maneira tradicional de desenvolvimento.<br />

Em seu blog, [Hawley 2004] publicou os resultados de uma pesquisa que ele<br />

mesmo realizou com a ajuda de seu colega de trabalho. Nesta pesquisa ele constatou<br />

que 92% dos desenvolvedores perceberam que TDD os forçaram a produzir código de<br />

alta qualidade. Constatou também, através dos códigos produzidos pelos participantes,<br />

que houve um incremento na qualidade do código, uma vez que eles tiveram 18% mais de<br />

sucesso nos testes de caixa-preta em comparação com os códigos produzidos da maneira<br />

tradicional.<br />

3.1. Desenho Simplificado e Evolucionário<br />

Escrevendo somente o necessário para os testes e removendo toda a duplicação, você automaticamente<br />

obtém um desenho que é perfeitamente adaptado para os requisitos atuais<br />

e igualmente preparado para todas as futuras funcionalidades [Beck 2002].<br />

Design simplificado reduz os custos porque ao escrever menos código para atender<br />

os requisitos, menos código existirá para ser mantido no futuro. Design simplificado é<br />

mais fácil de se construir, manter e entender.<br />

3.2. Refatoração<br />

Os testes lhe dão a confiança de que grandes refatorações não mudarão o comportamento<br />

do sistema, o que se conclui que, quanto maior a confiança, mais agressivamente você<br />

poderá conduzir refatorações em larga escala que estenderão a vida de seu sistema. A<br />

refatoração torna a elaboração dos próximos testes muito mais fácil [Beck 2002].<br />

Custos são reduzidos porque a refatoração contínua evita que o desenho se degrade<br />

com o passar do tempo, assegurando que o código continue fácil de ser entendido, mantido<br />

e modificado.<br />

3.3. Feedback Constante<br />

[Beck 2002], no último capítulo de sua publicação, afirma que TDD o ajuda a dar atenção<br />

aos problemas certos na hora certa, de forma que o desenho do software fica mais limpo<br />

e com muito menos defeitos. O TDD faz com que o programador ganhe confiança sobre<br />

seu código com o passar do tempo, isto é, à medida que os testes vão se acumulando (e<br />

melhorando), ele ganha confiança no comportamento do sistema. E ainda, à medida que<br />

o desenho é refinado, mais e mais mudanças se tornam possíveis.<br />

Outra vantagem do TDD que [Beck 2002] acredita poder explicar seus efeitos<br />

positivos, é a forma como ele encurta o ciclo de feedback sobre as decisões de desenho.<br />

Ele dura apenas segundos ou minutos, e é seguido pela reexecução dos testes dezenas ou<br />

centenas de vezes por dia. Ao invés de se projetar um desenho e então esperar semanas<br />

ou meses para outra pessoa sentir as dores ou glórias de sua consequência, o feedback<br />

emerge em segundos ou minutos, enquanto você tenta traduzir suas idéias em interfaces<br />

plausíveis.<br />

3.4. Suíte de <strong>Testes</strong> (Regressão)<br />

Usando TDD, os testes unitários são criados num momento onde a funcionalidade a ser<br />

implementada está mais bem definida na mente do programador, e depois podem e devem


ser utilizados para fazer testes de regressão. Uma suíte de testes automáticos feita por<br />

programadores reduz os custos de um software funcionando como uma rede de segurança<br />

de testes que capturam defeitos, problemas de comunicação e ambigüidades antes e permitem<br />

que o desenho possa ser modificado de forma incremental. Esta suíte de testes<br />

gerada pelo TDD é fundamental para viabilizar procedimentos de Integração Contínua 2 .<br />

3.5. Documentação Para Programadores<br />

A suíte de testes serve como uma documentação voltada para o programador que tem um<br />

entendimento mais rápido e facilitado do que uma parte do código faz através do código<br />

que o testa. Cada teste unitário especifica o uso apropriado de uma classe de produção<br />

[Langr 2005].<br />

4. Conclusões<br />

Esta técnica de desenvolvimento produz desenhos menos acoplados que são mais fáceis<br />

de manter, reduz altamente a quantidade de defeitos, e reforça a construção e manutenção<br />

apenas do que é realmente necessário. Finalmente, testes bem escrito atuam como um<br />

tipo de requisitos “executáveis” que ajudam a manter o entendimento compartilhado da<br />

equipe de desenvolvimento, sobre como o sistema de software representa os problemas<br />

do mundo real.<br />

Por outro lado, o fato de se ter um grande número de testes unitários passando<br />

com sucesso, pode passar uma falsa sensação de segurança, resultando na implementação<br />

de menos atividades de garantia de qualidade, como testes de integração e testes de<br />

conformidade.<br />

É importante ressaltar também que, esta técnica não garante a obtenção de níveis<br />

aceitáveis em certos aspectos do software final, como usabilidade e desempenho. Além<br />

disso, TDD não consegue mitigar riscos relacionados com a falta de requisitos ou com<br />

requisitos erroneamente definidos.<br />

Referências<br />

Astels, D. (2003). Test-Driven Development: A Practical Guide. Prentice Hall PTR.<br />

Beck, K. (1999). Extreme Programming Explained: Embrace Change. Addison Wesley.<br />

Beck, K. (2002). Test-Driven Development By Example. Addison Wesley.<br />

Bellware, S. (2009). http://www.tvagile.com/2009/08/13/good-test-better-code-fromunit-testing-to-behavior-driven-development/.<br />

Good Test, Better Code - From Unit<br />

Testing to Behavior-Driven Development (10:40).<br />

Fowler, M. (2006). Continuous integration.<br />

Friedman, L. (2009). Quality - an agile point of view. TE: Testing Experience, Setembro:16<br />

17.<br />

2 Segundo [Fowler 2006], integração contínua é uma pratica de desenvolvimento de software onde os<br />

membros de um time integram seu trabalho frequentemente, geralmente cada pessoa integra pelo menos<br />

diariamente, podendo haver múltiplas integrações por dia. Cada integração é verificada por um build automatizado<br />

(incluindo testes) para detectar erros de integração o mais rápido possível. Muitos times acham<br />

que essa abordagem leva a uma significante redução nos problemas de integração e permite que um time<br />

desenvolva um software coeso mais rapidamente.


Hawley, M. (2004). http://weblogs.asp.net/mhawley/archive/2004/04/15/114005.aspx.<br />

TDD Research Findings.<br />

James P. Womack, Daniel T. Jones, D. R. (1990). The machine that changed the world.<br />

Koskela, L. (2008). Test Driven: Pratical TDD and Acceptance TDD for Java Developers.<br />

Manning.<br />

Langr, J. (2005). Agile Java Crafting Code with Test-Driven Development. Prentice Hall<br />

PTR.<br />

Lewis, W. E. (2004). Software Testing and Continuous Quality Improvement. Auerbach,<br />

2 edition.<br />

Schwaber, K. (2004). Agile Project Management with Scrum. Microsoft Press.<br />

Tian, J. (2005). Software Quality Engineering: Testing, Quality Assurance, and Quantifiable<br />

Improvement. John Wiley & Sons.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!