Você está na página 1de 70

1

SUMÁRIO

1 INTRODUÇÃO..................................................................................... 4

2 PROCESSOS DE SOFTWARE ........................................................... 5

2.1 PROCESSOS DE SOFTWARE E SUAS ETAPAS ....................... 5

3 REQUISITOS DE UM SOFTWARE ..................................................... 7

3.1 REQUISITOS FUNCIONAIS ......................................................... 8

3.2 REQUISITOS NÃO FUNCIONAIS ................................................ 8

4 PROCESSO DE DESENVOLVIMENTO E GERENCIAMENTO DE UM


SOFTWARE .......................................................................................................... 12

5 PADRÕES DE PROJETO DE ARQUITETURA DE SISTEMAS ........ 15

5.1 DEFINIÇÃO E SURGIMENTO DOS PADRÕES DE


PROJETOS....... ................................................................................................ 16

5.2 VANTAGENS EM UTILIZAR PADRÕES DE PROJETOS .......... 18

6 QUAL É O MELHOR PADRÃO DE PROJETO PARA O SEU


SOFTWARE? ........................................................................................................ 20

7 TIPOS DE PADRÕES DE PROJETO ................................................ 24

7.1 CREATIONAL PATTERNS (PADRÕES DE CRIAÇÃO) ............. 24

7.2 STRUCTURAL PATTERNS (PADRÕES ESTRUTURAIS) ......... 25

7.3 BEHAVIORAL PATTERNS (PADRÕES COMPORTAMENTAIS)26

8 MÉTODOS ÁGEIS............................................................................. 28

8.1 CONCEITO DE MÉTODO ÁGIL ................................................. 29

8.2 FERRAMENTAS ELETRÔNICAS DE MÉTODOS ÁGEIS .......... 30


2
9 VALORES E PRINCÍPIOS ÁGEIS ..................................................... 32

10 PRINCIPAIS MÉTODOS ÁGEIS EXISTENTES ............................. 36

11 TEST-DRIVEN DEVELOPMENT ................................................... 44

11.1 SURGIMENTO DE UM MÉTODO DE DESENVOLVIMENTO


DIRIGIDO POR TESTES ................................................................................... 44

11.2 HISTÓRICO ................................................................................ 45

11.3 CONCEITOS DO TEST-DRIVEN DEVELOPMENT ................... 46

11.4 O TEST-DRIVEN DEVELOPMENT NO CICLO DE VIDA DO


SOFTWARE.... .................................................................................................. 50

11.5 DOCUMENTAÇÃO ..................................................................... 62

12 VANTAGENS E DESVANTAGENS DO TEST-DRIVEN


DEVELOPMENT ................................................................................................... 63

12.1 VANTAGENS DA UTILIZAÇÃO DO TEST-DRIVEN


DEVELOPMENT ................................................................................................ 64

12.2 DESVANTAGENS DA UTILIZAÇÃO DO TEST-DRIVEN


DEVELOPMENT ................................................................................................ 65

13 REFERÊNCIAS BIBLIOGRÁFICAS ............................................... 68

3
1 INTRODUÇÃO

Prezado aluno!

O Grupo Educacional FAVENI, esclarece que o material virtual é


semelhante ao da sala de aula presencial. Em uma sala de aula, é raro – quase
improvável - um aluno se levantar, interromper a exposição, dirigir-se ao professor
e fazer uma pergunta, para que seja esclarecida uma dúvida sobre o tema tratado.
O comum é que esse aluno faça a pergunta em voz alta para todos ouvirem e todos
ouvirão a resposta. No espaço virtual, é a mesma coisa. Não hesite em perguntar,
as perguntas poderão ser direcionadas ao protocolo de atendimento que serão
respondidas em tempo hábil.
Os cursos à distância exigem do aluno tempo e organização. No caso da
nossa disciplina é preciso ter um horário destinado à leitura do texto base e à
execução das avaliações propostas. A vantagem é que poderá reservar o dia da
semana e a hora que lhe convier para isso.
A organização é o quesito indispensável, porque há uma sequência a ser
seguida e prazos definidos para as atividades.
Bons estudos!

4
2 PROCESSOS DE SOFTWARE

Um dos itens primordiais de fator de sucesso em empresas de


desenvolvimento de software é a utilização de um processo de software, que pode
ser definido brevemente como um conjunto de atividades exigidas no
desenvolvimento de um sistema de software. Logo, pode-se dizer que se trata de
um conjunto de atividades e resultados que juntos produzem um software. Essas
atividades são relacionadas entre elas e operam de acordo com padrões
preestabelecidos para alcançar um objetivo ou resultado desejado. Ou seja, a partir
dessa definição, você pode produzir um software de alta qualidade e custo baixo
Sommerville (2011).
A partir desses conceitos, pode-se considerar que um processo de software
pode ser visto como um conjunto de atividades, métodos, ferramentas e práticas
que podem ser utilizadas para construir um produto. Entre as atividades
relacionadas ao processo de software, estão: especificação, desenvolvimento,
verificação e manutenção Sommerville (2011).

2.1 PROCESSOS DE SOFTWARE E SUAS ETAPAS

As principais fases de um processo de software são: a especificação de


requisitos, na qual são traduzidas as necessidades ou requisitos operacionais para
a descrição da funcionalidade a ser implementada; o projeto de sistema, no qual
tudo o que foi traduzido terá uma descrição item a item de componentes necessários
para a codificação do software; a programação propriamente dita, em que ocorre a
codificação que controla o sistema e é implementada a lógica necessária; a
verificação, onde se observa se todos os requisitos iniciais foram implementados e
o objetivo alcançado Sommerville (2011).

5
Segundo Sommerville (2011), podemos identificar as seguintes atividades
no processo de software:
Especificação

• Engenharia de sistema: solução para o problema em questão,


envolve questões amplas, inclusive que sejam a parte em relação ao
software, porém pertençam ao problema a ser solucionado.
• Análise de requisitos: área em que as necessidades para atender
ao cliente são levantadas, tendo como principal objetivo especificar
os requisitos documentando-os.
• Especificação do sistema: ocorre a descrição funcional do
software, incluindo planos de testes para verificar se está adequado.

Projeto

• Arquitetura: neste item, ocorre o desenvolvimento do modelo


conceitual para o software, composto de módulos que podem ser
independentes.
• Interface: é definida e estudada a interface de comunicação para
cada módulo.
• Detalhamento: neste item, os módulos são definidos e podem ser
traduzidos para pseudocódigos.

Implementação

Codificação: a implementação e o desenvolvimento em si do software.

Validação

6
• Teste unitário: ocorre a realização de testes para verificar se há erros
e se o comportamento está adequado.
• Integração: união de diferentes módulos do software em um só,
assim como a verificação da interação entre eles quando estão
funcionando em conjunto.

Manutenção e evolução

• O software desenvolvido e implementado entra em um ciclo que


abrange todas as fases anteriores.

3 REQUISITOS DE UM SOFTWARE

Requisitos são condições que devem ser alcançadas, ou seja, é o que um


software ou componente deve possuir para satisfazer uma especificação de um
sistema a fim de atender às necessidades dos clientes, restrições e serviços que
devem ser contemplados. Normalmente são identificados a partir das regras de
negócio estabelecidas, que estão diretamente ligadas à área específica em que o
software será desenvolvido. Durante o levantamento de requisitos, os
desenvolvedores devem ter conhecimento sobre o que o sistema deverá
proporcionar e compreender a necessidade do usuário. Entre os requisitos, existem
os funcionais e os não funcionais Sommerville (2011).

7
3.1 REQUISITOS FUNCIONAIS

Requisitos funcionais são os que abordam o que o software deverá fazer,


como deverá reagir a entradas específicas e o comportamento. Dependem do tipo
de software que será desenvolvido, de quem o utilizará e da maneira como é feita
a escrita dos requisitos pela empresa. Ou seja, pode ser descrito de uma forma mais
abstrata para que o usuário do sistema tenha uma compreensão mais fácil ou
podem ser mais específicos tecnicamente, com entradas, saídas, exceções e
restrições Sommerville (2011).
Como um dos problemas em desenvolvimento de software, pode-se citar a
imprecisão na especificação dos requisitos, o que pode ocasionar atrasos e
aumento de custos na engenharia do software. Por essa razão, preza-se que seja
sempre completa e consistente, sendo todos os serviços requeridos pelo usuário
explícitos plenamente Sommerville (2011).

3.2 REQUISITOS NÃO FUNCIONAIS

Requisitos não funcionais são restrições aos serviços ou às funções


oferecidos pelo software, incluindo normas e timing e, normalmente, aplicam-se ao
software como um todo. Não estão relacionados diretamente a serviços específicos
que sejam oferecidos pelo software, podem estar relacionados às propriedades do
sistema, como: tempo de retorno, confiabilidade. Normalmente especificam ou
restringem características do sistema e frequentemente são mais críticos que os
funcionais, ou seja, se deixar de atendê-los, pode ser que o sistema seja inutilizado
Sommerville (2011).
Os requisitos não funcionais podem afetar a arquitetura do software,
assegurando que sejam cumpridos requisitos de desempenho, organizando o
sistema para que seja minimizada a comunicação entre componentes. Você poderá

8
verificar que um único requisito não funcional poderá gerar outros requisitos
funcionais relacionados a ele, os quais possam definir serviços necessários, como
um requisito de proteção. A Figura 1 apresenta tipos de requisitos não funcionais,
segundo Sommerville (2011).

Fonte: Adaptado de Sommerville (2011)

Geralmente, os requisitos não funcionais conflitam com outros requisitos funcionais


ou não funcionais.
A especificação de requisitos de software nada mais é do que um documento oficial,
em que os desenvolvedores baseiam-se para implementar o software solicitado.
Esse documento deve incluir requisitos de usuário e uma especificação detalhada

9
dos requisitos (funcionais e não funcionais) de sistema, ou seja, esses documentos
são essenciais quando alguém está desenvolvendo um sistema. O Quadro 1 mostra
usuários desses documentos e como eles o utilizam, conforme Kotonya e
Sommerville (1998).

Fonte: Adaptado de Sommerville (2011)

Dessa forma, você deverá incluir em documento de requisitos detalhes que


dependerão do tipo de software que deverá ser desenvolvido e o processo utilizado
Sommerville (2011).
O quadro a seguir apresenta uma maneira de organizar o documento de
requisitos com base na norma IEEE (IEEE, 1998).

10
11
Fonte: IEEE (IEEE, 1998).

4 PROCESSO DE DESENVOLVIMENTO E GERENCIAMENTO DE UM


SOFTWARE

Conforme abordado anteriormente, o documento de especificação é um


item primordial para que o software seja desenvolvido de acordo com as
necessidades dos clientes, com as restrições necessárias, abordando
confiabilidade, portabilidade, segurança e usabilidade, assim como desempenho e
hardware necessário. A Figura abaixo mostra as fases e cada uma de suas etapas
antes do desenvolvimento do software Sommerville (2011).

12
Fonte: Adaptado de Sommerville (2011)

A análise e a elicitação de requisitos envolvem vários tipos de pessoas de


uma organização, geralmente o stakeholder, que inclui usuários finais que
interagirão direto com o sistema, e alguma outra pessoa que será afetada direta ou
indiretamente pelo software Sommerville (2011).

13
O gerenciamento de projetos em software leva em consideração primeiro a
qualidade, a produtividade e a redução de riscos. Os pontos técnicos devem incluir
a definição do ciclo de vida e tipos de planos a serem utilizados para testes,
documentação, desenvolvimento, qualidade e gerenciamento Sommerville (2011).
No quesito ciclo de vida do software, identificam-se três fases: definição,
desenvolvimento e operação. Em definição, os requisitos são determinados e a
viabilidade é estudada, assim como o planejamento de atividades é elaborado. Na
fase do desenvolvimento, são realizadas atividades para a produção do software,
como: concepção, especificação, design de interface, prototipação, arquitetura,
codificação e verificação. Na fase da operação, o software será utilizado pelos
usuários e podem ocorrer manutenções, para correções ou evoluções Sommerville
(2011).
Os principais motivos para problemas apresentados estão relacionados a
falhas no gerenciamento de projetos durante a fase de desenvolvimento, segundo
Standish Group (1994). Uma das tarefas de um gestor de projetos é identificar as
partes mais difíceis e buscar soluções eficientes Sommerville (2011).
O gestor de projetos deve trabalhar com ideias e com pessoas, tendo como
principais atividades planejamento, assessoria, organização, saber dirigir e
controlar o projeto. Da mesma forma que deve ter comprometimento com equipe,
prazos, custos e qualidade em suas entregas Sommerville (2011).
Como há muitas mudanças de requisitos, o ciclo mostrado na figura
apresentada deve ser repetido toda vez que for necessário. As novas técnicas com
metodologias ágeis facilitam a vida dos gerentes de projeto desde que estes tenham
uma equipe qualificada e comprometida, pois podem facilitar a adaptação às
mudanças que ocorrem no decorrer dos projetos Sommerville (2011).
É importante que aspectos como arquitetura de sistema, linguagem de
programação, sistema gerenciador de banco de dados e padrão de interface gráfica
sejam considerados na fase do projeto Sommerville (2011).

14
É fundamental que gerentes de projeto estejam atualizados sobre novas
tecnologias, ferramentas, metodologias, modelos e melhores práticas para que o
projeto tenha sucesso e o desenvolvimento seja eficaz e eficiente Sommerville
(2011).

5 PADRÕES DE PROJETO DE ARQUITETURA DE SISTEMAS

O processo de desenvolvimento de software consiste em inúmeras


atividades determinadas e organizadas, que têm como objetivo resolver um
problema da área de tecnologia da informação. O objetivo principal dessas
atividades é satisfazer as necessidades dos clientes/ usuários do sistema. Para
tanto, é preciso analisar os requisitos do sistema e projetar e implementar um código
padronizado, para evitar erros e falhas Zenker (2020).
Padronizar consiste em empregar técnicas e padrões que auxiliam no
desenvolvimento e aumentam a produtividade, a segurança e a qualidade no
projeto. Um padrão é um molde, um exemplo, um protótipo, um paradigma ou uma
referência de algo a seguir. Um projeto é um desenho, uma planta, um esquema,
um plano ou um programa Zenker (2020).
Padrões de projeto (do inglês design patterns) são alternativas ou modelos
de soluções para problemas encontrados no desenvolvimento de um projeto de
software independente do paradigma; porém, sua aplicabilidade maior é no
paradigma orientado a objetos. Os padrões de projetos facilitam a reutilização de
soluções e arquiteturas de software de forma fácil e flexível, reduzindo a
complexidade do projeto e resolvendo os problemas apresentados Zenker(2020).

15
5.1 DEFINIÇÃO E SURGIMENTO DOS PADRÕES DE PROJETOS

Os padrões de projetos, comumente conhecidos como design patterns, são


modelos, isto é, referências aplicadas ao projeto, trazendo soluções para problemas
específicos do desenvolvimento do projeto de software orientado a objetos. Os
padrões são aplicáveis a outros paradigmas, porém, não são tão relevantes quanto
no paradigma orientado Zenker(2020).
Por meio dos design patterns, é possível definir nomes e descrever o
problema e a solução a ser aplicada ao projeto. Eles trazem exemplos de
implementações e uma organização geral de classes e objetos. Os padrões de
projetos facilitam a reutilização de soluções e arquiteturas bem-sucedidas na
construção de um projeto com paradigma orientado a objetos. Além disso, eles
promovem a organização no código e garantem ao programador um código limpo e
padronizado, além de melhorar a documentação e a manutenção do sistema, ao
fornecer uma especificação de interações entre os objetos das classes
Zenker(2020).
Em resumo, os padrões de projetos auxiliam o projetista, o desenvolvedor
e o analista a obterem um projeto adequado, sendo uma solução para um problema
em um determinado contexto Zenker(2020).
Os problemas surgem com o desenvolvimento do projeto, podendo ser uma
dificuldade em desenvolver ou apenas um desafio. O contexto determina qual
padrão deve ser aplicado para a resolução do problema. A solução surge com a
escolha do padrão (pattern) adequado ao projeto em questão. Todo padrão de
projeto possui elementos ou componentes essenciais, conforme listado a seguir.

• Nome: descreve a essência do padrão; é uma referência para poder


escrever o problema do projeto.
• Objetivo: descreve como o padrão atua, em que modelo de software
se aplica.

16
• Problema: descreve o problema, em que situação se aplica o padrão.
• Contexto: descreve uma situação que complemente o problema.
• Solução: descreve a solução; é uma descrição abstrata de um
problema e de como as classes e os objetos o resolverão.
• Consequências: descreve as vantagens e desvantagens da
utilização do padrão; são críticas para a avaliação de alternativas de
projetos e a compreensão de custos e benefícios para aplicação no
software desenvolvido Zenker(2020).

O padrão de projetos surgiu como um conceito de arquitetura, no final dos


anos 1970, documentado no livro A Pattern Language: Towns, Buildings,
Construction. Nesse livro, os arquitetos Christopher Alexander, Sara Ishikawa e
Murray Silverstein catalogaram 253 tipos de problemas de projeto e desafios e
analisaram cada situação, descrevendo e propondo um padrão de solução. O livro
foi publicado em português em 2012, com o nome Uma Linguagem de Padrões —
a Pattern Language Zenker(2020).
Nos anos 1980, os engenheiros de software Kent Beck e Ward Cunninghan
começaram a aplicar a ideia de padrões na área de programação em uma palestra
denominada "Utilizando a linguagem dos padrões para programação orientada a
objetos”, em tradução livre. Porém, somente nos anos 1990, os padrões ganharam
credibilidade, após serem publicados no livro Design Patterns — Elements of
Reusable Object-Oriented Software, escrito por Erich Gamma, Richard Helm, Ralph
Johnson e John Vlissides Zenker(2020).
O livro apresentou 23 padrões de projetos. Os autores ficaram conhecidos
como a gangue dos quatro (GoF, do inglês gang of four), termo utilizado nos
padrões definidos no livro Zenker(2020).
Os padrões facilitam o desenvolvimento do projeto, conforme apontam
Gamma et al. (2000, p. 17):

17
Uma coisa que os melhores projetistas sabem que não devem fazer é
resolver cada problema a partir de princípios elementares ou do zero.
Quando encontram uma boa solução, eles a utilizam repetidamente.
Consequentemente, você encontrará padrões de classes e de
comunicação entre objetos. Esses padrões resolvem problemas
específicos de projetos e tornam os projetos orientados a objetos mais
flexíveis e, em última instância, reutilizáveis.

5.2 VANTAGENS EM UTILIZAR PADRÕES DE PROJETOS

Os padrões de projetos são modelos que já foram utilizados, implementados


e testados em diversos projetos, o que traz segurança ao utilizá-los, além de outras
vantagens, descritas a seguir Zenker(2020).

• Com o uso de padrões de nomenclatura, o projeto possuirá nomes


estandardizados, trazendo referência e credibilidade para o software
desenvolvido.
• Melhorar técnicas e princípios da programação orientada a objetos,
como implementação de herança, composição e polimorfismo.
• Aumentar a organização e a manutenção de projetos, já que esses
padrões se baseiam em baixo acoplamento entre as classes e
padronização do código.
• Melhorar o desenvolvimento de projetos tanto individualmente
quanto em equipe.
• Implementar hierarquias de herança, diminuindo o tamanho do
projeto e aprimorando o mesmo.
• Facilitar a manutenção do projeto e a edição do código.
• Utilizar o padrão para a refatoração de um código ruim, altamente
acoplado e de baixa coesão.

18
Veja a seguir a terminologia relacionada ao programa orientado a objetos:

• Classe: representa um conjunto de objetos com


características afins. Uma classe define o comportamento do
objeto, por meio de métodos, e quais estados ele é capaz de
manter, por meio de atributos.
• Atributos: são características de um objeto. Basicamente,
trata-se da estrutura de dados que vai representar a classe.
• Métodos: definem as habilidades dos objetos. São ações que
o objeto pode fazer ou sofrer.
• Objeto: instância da classe, elemento que foi gerado por meio
da classe.
• Interface: é um contrato entre a classe e o mundo externo.
Quando uma classe implementa uma interface, ela está
comprometida a fornecer o comportamento publicado pela
interface.
• Abstração: é a habilidade de se concentrar nos aspectos
essenciais de um contexto qualquer, ignorando características
menos importantes ou acidentais. Em modelagem orientada a
objetos, uma classe é uma abstração de entidades existentes
no domínio do sistema de software.
• Associação: é o mecanismo pelo qual um objeto utiliza os
recursos de outro. Pode tratar-se de uma associação simples
"usa um" ou de um acoplamento "parte de".
• Coesão: é quando as tarefas que um elemento realiza estão
relacionadas a um mesmo conceito; é o princípio da
responsabilidade única, isto é, a ideia de que a classe não
deve assumir responsabilidades que não são suas.

19
• Sobrecarga: é a utilização do mesmo nome para símbolos ou
métodos com operações ou funcionalidades distintas.
Geralmente os métodos se diferenciam pela sua assinatura.
• Acoplamento: significa o quanto uma classe depende da
outra para funcionar. Surge da associação entre as classes;
conforme for a dependência entre ambas, surge o termo
“fortemente acopladas”.
• Refatoração: é o processo de alterar um software de maneira
que não mude o seu comportamento externo e ainda melhore
a sua estrutura interna, modificando apenas a estrutura
interna do código.

6 QUAL É O MELHOR PADRÃO DE PROJETO PARA O SEU SOFTWARE?

Encontrar o padrão de projeto adequado ao software é difícil. Os padrões


de GoF, segundo Gamma et al. (2000), apontam 23 padrões na lista de escolhas.
Porém, é fundamental seguir alguns critérios, com o objetivo de solucionar o
problema do projeto sem cometer erros e tornando o projeto o mais padronizado e
organizado possível. Observe a figura abaixo:

20
Fonte: Gamma et al. (2000)

Cada padrão de projeto é dividido em seções, consistindo em critérios que


apresentam e justificam seu uso, possibilitando comparações, entendimento e
aplicabilidade Zenker(2020). Entre os critérios para a escolha do melhor padrão,
destacam-se os seguintes:

21
1. Considerar como os padrões de projeto solucionam problemas de
projeto. Avaliar a necessidade do software e qual é a intenção ao
utilizar o padrão.
2. Examinar qual é a intenção do padrão, o que faz, de fato, o padrão
de projeto, quais são os princípios do modelo e se o mesmo
solucionará o problema em questão.
3. Estudar como os padrões se relacionam. Avaliar, por meio da tabela
de escopo e propósitos do projeto (Quadro 1), qual é a relação
existente entre os padrões.
4. Estudar as semelhanças existentes entre os padrões. Verificar
semelhanças entre os grupos de padrões de criação, estruturados e
comportamentais.
5. Examinar uma causa de reformulação de projeto.
6. Considerar o que deveria ser variável no seu projeto; ou seja, em vez
de considerar o que pode forçar uma mudança em um projeto, deve-
se considerar o que se deseja mudar sem necessitar reprojetá-lo.

22
Fonte: Adaptado de Gamma et al. (2000).

Analisando o Quadro acima, percebe-se que o primeiro critério abordado é


a finalidade do padrão, separada em três propósitos: criação, estrutura e
comportamento. Além do propósito, há o escopo definido, que estabelece se o
padrão é relacionado a classes e subclasses ou envolve objetos. Os padrões
relacionados a classes e subclasses são estáticos, enquanto os padrões
relacionados a objetos são dinâmicos, isto é, podem ser modificados no tempo real
do projeto.

23
7 TIPOS DE PADRÕES DE PROJETO

Seguindo o repositório GoF definido no livro de Gamma et al. (2000), os


padrões são listados de acordo com o contexto aplicado e o tipo de problema. Os
principais padrões de projetos são divididos em segmentos de criação (creational
patterns), estrutura (structural patterns) e padrões de comportamento (behavioral
patterns) Zenker(2020).

7.1 CREATIONAL PATTERNS (PADRÕES DE CRIAÇÃO)

O objetivo desse tipo de padrão é a abstração da instância de objetos. É


possível criar um objeto sem se preocupar com o todo envolvido na criação desse
componente. Esse padrão abstrai ou adia o processo de criação, tornando o sistema
independente de como os seus objetos são criados. O mesmo pode impedir que um
sistema crie mais de um objeto de uma classe, ou pode postergá-lo até o tempo de
execução Zenker(2020).
Suponha o projeto do jogo Imagem e Ação, em que os jogadores
desenharão objetos para que os outros adivinhem. O usuário pode desenhar
qualquer forma, sendo figuras vetoriais geométricas ou vetoriais à mão livre.
Supondo que cada forma no programa de desenho seja representada por um objeto,
no tempo de execução do projeto, não se sabe a forma que o usuário desenhará.
Com base na entrada do jogador, o programa deve ser capaz de determinar em que
classe instanciar um objeto. Se o jogador criar um retângulo na interface gráfica do
utilizador (GUI, do inglês graphical user interface), nosso programa deve estar
preparado para a instância de um objeto da classe Rect(). Quando o jogador decide
qual objeto desenhar, o programa deve determinar em que subclasse específica
deve instanciar esse objeto Zenker(2020).
Os padrões de criação são os seguintes.

24
• Abstract Factory: fornece uma interface para a criação de conjuntos
de objetos relacionados ou dependentes, sem precisar especificar
sua classe
• Builder: separa a construção de um objeto complexo da sua
representação. Possibilita que seu processo de construção crie
diferentes representações
• Factory Method: define a interface para a criação de um objeto, mas
são as subclasses que decidem qual classe deve ser instanciada.
• Prototype: especifica os tipos de objetos a serem criados usando
uma instância prototípica e criando objetos copiando esse protótipo
• Singleton: garante que a classe tenha somente uma instância e
fornece um ponto global de acesso a ela.

7.2 STRUCTURAL PATTERNS (PADRÕES ESTRUTURAIS)

O objetivo desse padrão é a organização e a estruturação das classes e


dos seus relacionamentos com os objetos. Ao contrário do padrão de criação, o
padrão de estrutura é voltado para os objetos, descrevendo maneiras de montá-los,
isto é, a maneira como as classes e os objetos serão compostos para formar
estruturas maiores. A flexibilidade obtida pela composição de objetos provém da
capacidade de mudar a composição em tempo de execução Zenker(2020).
Segundo Ricardo (2006), do site DevMedia, um exemplo do uso do padrão
estruturado é no framework Hibernate. Este faz uso do padrão proxy ao executar a
técnica utilizada para acessar o banco de dados apenas quando for necessário. Em
muitas buscas, o Hibernate usa o método session.load(id); nesse momento, um
proxy para o objeto real é retornado. Nesse caso, o objeto ainda não está
completamente preenchido, pois nenhum SQL foi realizado até esse momento.

25
Apenas quando uma propriedade desse objeto (método getX) ou um
relacionamento (por exemplo, empresa.getFuncionarios()) for chamado, a consulta
no banco será realizada — tudo isso de forma transparente para o cliente
Zenker(2020).
Os padrões de estrutura são os seguintes.

• Adapter: converte a interface de uma classe em outra interface


esperada pelo cliente. O Adapter permite que as classes trabalhem
em conjunto para promover essa mudança.
• Bridge: separa uma abstração da sua implementação, permitindo
uma variação individual de cada uma.
• Composite: compõe objetos em estruturas hierárquicas, como
árvores. Trata objetos individuais e composições de objetos de forma
uniforme.
• Decorator: atribui de forma dinâmica responsabilidades adicionais a
um objeto.
• Façade: fornece uma interface unificada para um conjunto de
interfaces em subsistema.
• Flyweight: suporta grandes quantidades de objetos de forma
eficiente, por meio de compartilhamento.
• Proxy: fornece um objeto representante (surrogate) ou marcador de
outro objeto.

7.3 BEHAVIORAL PATTERNS (PADRÕES COMPORTAMENTAIS)

O objetivo é delegar responsabilidades, definindo como os objetos devem


se comportar e se comunicar. Esses padrões se concentram nos algoritmos
Zenker(2020).

26
São 11 os padrões comportamentais, que são descritos a seguir
Zenker(2020).

• Chain of Responsibility: evita o acoplamento de remetente de uma


solicitação ao destinatário, dando chance ao objeto para tratar a
solicitação.
• Command: encapsula uma solicitação como objeto, permitindo
parametrizar clientes com diferentes solicitações, enfileirando ou
registrando os “logs” de solicitações.
• Interpreter: define para a linguagem uma representação gramatical
dentro do interpretador.
• Iterator: possibilita o acesso sequencial dos elementos de uma
agregação de objetos, sem a necessidade de expor sua
representação subjacente
• Mediator: define um objeto que encapsula a forma como um
conjunto de objetos interage
• Memento: captura e externaliza um estado interno do objeto sem
violar seu encapsulamento, possibilitando restaurar para esse estado
— por exemplo, um controle de históricos de ações.
• Observer: define uma dependência um-para-muitos entre objetos;
quando um objeto muda, todos os seus dependentes são notificados
e atualizados automaticamente.
• State: permite que o objeto altere seu comportamento quando o
estado interno for modificado.
• Strategy: define uma família de algoritmos, encapsulando cada um
e os tornando intercambiáveis.
• Template Method: define o esqueleto de um algoritmo em uma
operação, postergando a definição de alguns passos para
subclasses.
27
• Visitor: representa uma operação a ser executada sobre os
elementos da estrutura de um objeto

8 MÉTODOS ÁGEIS

Atualmente, dois cenários impactam a rotina dos desenvolvedores: o


cenário da big data e o cenário da Internet das Coisas. Profissionais que estudam
software e atuam na área de desenvolvimento de software, sistemas e sites são
forçados a implementar tecnologias novas a todo momento. A Internet das Coisas
fez com que câmeras, smartphones e relógios fiquem conectados à internet a todo
momento, e as empresas veem nisso uma oportunidade para estudar
comportamentos através dos logs e registros das pessoas nos sistemas. Quem quer
que trabalhe na área certamente será forçado a adaptar software rapidamente às
tecnologias que surgem diariamente. Por isso, a rotina dos desenvolvedores é
recheada de adrenalina (Andrade, 2020).
Em pouco tempo, vimos os sites que possuíam linguagens HTML 4, CSS ,
PHP 5 e JavaScript se tornarem HTML 5 com suas animações, CSS 3, com suas
decorações extravagantes, PHP 7, com sua agilidade e códigos novos, e JavaScript
React, Angular e JQuery, trazendo novas formas de controlar e manipular os
elementos frontais das páginas. Além disso, você deve ter percebido que os bancos
de dados SQL ganharam a companhia dos bancos NoSQL, que chegaram com
agilidade para sites que contêm muita interação com pessoas. Na criação de
software, percebemos que o que antes era feito através de Ionic, um framework
JavaScript que cria aplicativos com plugins, hoje é feito através de React Native,
que traz experiências mais satisfatórias ao usuário e usa a linguagem nativa dos
aparelhos mobiles (Andrade, 2020).
Neste cenário, várias formas de planejamento de criação de software
disputam as decisões das equipes que desenvolvem, e disso surgem dúvidas
28
quanto ao critério de escolha do método de desenvolvimento de software mais
dinâmico e condizente com o tempo em que vivemos. De acordo com Sommerville
(2011), em 1980, com o surgimento das linguagens de quarta geração, e em 1990,
com o surgimento de metodologias ágeis, como a Metodologia de Desenvolvimento
de Sistemas Dinâmicos e a Metodologia Extreme Programming, os
desenvolvedores se viram forçados a mudar a forma de trabalho. Vamos discutir um
pouco sobre isso neste capítulo Andrade, (2020).

8.1 CONCEITO DE MÉTODO ÁGIL

O desenvolvimento ágil envolve mudanças rápidas e prioriza-se, às vezes,


agilidade frente à qualidade — alguns analistas dizem que este método é uma
resposta ao cenário tecnológico. Após se fazer um planejamento de etapas de
requisitos, é comum ter que se deparar com mudanças dos próprios requisitos, e
isso é aceito neste método de desenvolvimento, pois não impossível antever todas
as necessidades do mercado, visto que elas mudam com frequentemente; em
alguns casos, os requisitos mudam depois da entrega do projeto (SOMMERVILLE,
2011).
De acordo com Amaral et al. (2012, p. 21) o conceito de ágil pode ser visto
como:

[...] é uma abordagem fundamentada em um conjunto de princípios, cujo


objetivo é tornar o processo de gerenciamento de projetos mais simples,
flexível e iterativo, de forma a obter melhores resultados em desempenho
(tempo, custo e qualidade), menos esforço em gerenciamento e maiores
níveis de inovação e agregação de valor para o cliente.

O desenvolvimento ágil é feito em equipes multidisciplinares, onde os


processos são feitos em espiral e as equipes priorizam conversas em detrimento da
documentação, ou seja, a rigidez é menor. Aqui, é mais importante a funcionalidade

29
do software do que a documentação; é mais importante satisfazer as necessidades
do cliente do que seguir um plano. No método ágil, os colaboradores têm perfil
motivado, as entregas são semanais e não mensais, o que facilita o
acompanhamento da satisfação do cliente. Logo, neste modelo, as adaptações
falam mais alto do que a disciplina, e o processo de criação de software é
transparente, o cliente vê tudo, o que ajuda na customização, conforme Sommerville
(2011). No método ágil, as equipes são pequenas, com alto nível técnico, feedbacks
constantes, as reuniões são rápidas — duram geralmente 15 minutos — e muitas
vezes são feitas em pé, e cada reunião gera um plano de ação, em outras palavras,
um conjunto de atividades a serem realizadas em um intervalo de tempo
determinado. A maioria dos métodos ágeis foi criada na década de 1990, e eles
serão explicados mais adiante (Andrade, 2020).

8.2 FERRAMENTAS ELETRÔNICAS DE MÉTODOS ÁGEIS

Que tal falarmos sobre ferramentas de gestão? O primeiro passo para criar
um painel de metodologia ágil é escolher o seu modelo de gestão, estes modelos
denominados Scrum, Kanban, entre outros, serão explicados posteriormente, mas
precisamos mencionar que as empresas estão usando preferencialmente dois sites:
Trello e Jira (Andrade, 2020).
O Trello é uma ferramenta de gestão on-line para métodos ágeis que auxilia
na organização de tarefas e possui três versões. O Quadro 1 compara as três
versões desta ferramenta. A primeira é o plano básico, que é gratuito e, mesmo
assim, permite vários usuários, porém não tem todas as ferramentas dos outros
planos. A segunda versão do Trello, chamada Business Class, é paga e possui, por
exemplo, relação com o Github. Hoje muitas empresas de tecnologia usam
programas como o Github a fim de salvar versões de cada alteração do código
automaticamente no servidor da plataforma. A terceira versão, o plano Enterprise,

30
também é paga e possui muitas ferramentas de gerenciamento de acessos a pastas
e a convites, entre outras funcionalidades administrativas (Andrade, 2020).

Fonte: Adaptado de Trello (2020)

O Jira também é uma ferramenta on-line de gestão ágil muito usada em


métodos ágeis. Esta ferramenta é mais complexa que o Trello e possui maior
processamento e velocidade, seu suporte é muito completo, atende 24 horas por
dia, e foi desenvolvido para projetos de software (Andrade, 2020).

31
O Quadro 2 mostra as utilidades do Jira e compara três planos: o básico,
gratuito, e os demais, Standart e Premium, sendo este último o mais caro (Andrade,
2020).

Fonte: Adaptado de Atlassian (c2020).

9 VALORES E PRINCÍPIOS ÁGEIS

De acordo com o site do Manifesto Ágil (BECK et al., c2001), no ano 2001,
em Utah, nos EUA, 17 profissionais que praticavam metodologias ágeis se reuniram
para praticar Snowbird e conversar sobre métodos de planejamento de software.

32
Criaram, portanto, um documento, chamado de grito de guerra, o Manifesto Ágil,
que possui quatro valores (contidos na coluna da esquerda na Figura 1). Estes
valores priorizam os pontos a seguir.

1. Pessoas frente aos processos — Este tópico objetiva favorecer


relacionamentos no ato da construção do software.
2. Funcionamento versus documentação — Este tópico objetiva
favorecer a funcionalidade da criação de software, e não somente o
design.
3. Colaboração do cliente, a funcionalidade da criação de software —
Este tópico objetiva favorecer a interação contínua com o cliente, a
fim de compreender seus desejos e anseios com mais precisão.
4. Consertar problemas e se adaptar a mudanças — Este tópico
objetiva favorecer uma construção dinâmica e não engessada, onde
consertar problemas é mais importante que manter a burocracia.

33
Fonte: Adaptada de Isotani e Rocha (2020).

Perceba o quanto esses valores são aplicáveis. Não se trata de deixar de


se organizar ou de documentar, obviamente, mas de tornar o trabalho mais
funcional e orgânico. Considere que os profissionais da área de programação ficam
sobrecarregados e que a área de tecnologia é estressante; há muita demanda para
pouco profissional, e a tendência é aumentar a necessidade de profissionais
(Andrade, 2020).
Uma situação que pode acontecer durante o desenvolvimento de um
software, por exemplo, é, apesar de haver um plano de ação, as pessoas
perceberem, em meio ao processo, a necessidade de alterações ou de inclusão de
novas funcionalidades. Outro exemplo seria, na criação de um app, constatar que
os dados precisam ficar em uma tabela temporária, e então ter que parar tudo e
criar um banco de dados temporário no painel do servidor (Andrade, 2020).

34
Agora, imagine que você tem que ficar documentando os detalhes de tudo
que fizer. Os programadores ficariam mais sobrecarregados ainda, pois além de
programar eles teriam que documentar. Neste ponto, ferramentas como o Github
ajudam, pois salvam automaticamente as versões (Andrade, 2020).
Imagine agora que você não permite que seus funcionários mudem um
pouco o curso? Isso acabaria atrapalhando um atributo muito importante:
funcionalidade! Por isso devemos seguir, sim, as boas práticas, sem, contudo,
negligenciar o tempo de execução, pois cada minuto poderia ser um recurso a mais
no seu software (Andrade, 2020).
Falamos dos quatro valores do Manifesto Ágil. Vejamos agora seus 12
princípios desenvolvimento de software? Eles estão presentes do próprio site oficial
do Manifesto Ágil (BECK et al., 2001).

• Nossa prioridade é satisfazer o cliente através da entrega contínua e


adiantada de software com valor agregado.
• Aceitar mudanças de requisitos, mesmo no fim do desenvolvimento.
Processos ágeis se adequam a mudanças, para que o cliente possa
tirar vantagens competitivas.
• Entregar frequentemente software funcionando, de poucas semanas
a poucos meses, com preferência à menor escala de tempo.
Indivíduos e interação entre eles mais que processos e ferramentas.
• Pessoas de negócio e desenvolvedores devem trabalhar diariamente
em conjunto por todo o projeto.
• Construir projetos em torno de indivíduos motivados, dando a eles o
ambiente e o suporte necessário e confiando neles para fazer o
trabalho.
• O método mais eficiente e eficaz de transmitir informações para e
entre uma equipe de desenvolvimento é por meio de conversa face
a face.

35
• Software funcionando é a medida primária de progresso.
• Os processos ágeis promovem desenvolvimento sustentável. Os
patrocinadores, desenvolvedores e usuários devem ser capazes de
manter um ritmo constante indefinidamente.
• Contínua atenção à excelência técnica e bom design aumentam a
agilidade.
• Simplicidade: arte de maximizar a quantidade de trabalho não
realizado é essencial.
• As melhores arquiteturas, requisitos e designs emergem de times
auto-organizáveis.
• Em intervalos regulares, a equipe reflete sobre como se tornar mais
eficaz, e então refina e ajusta seu comportamento de acordo.

Como você pode perceber, é um método poderoso, para quem já atua com
programação ele faz muito sentido. O sistema tradicional se mostra lento: nele, os
clientes chamam a empresa de criação de software, e para fazer a elicitação são
necessárias longas visitas técnicas, análises de documentos, entrevistas e análises
de processos, para então dar uma data relativamente demorada com um valor
relativamente alto para entregar a aplicação. Resultado? Alto custo e lentidão. No
sistema ágil o processo é mais fatiado e incrementado. Falaremos agora sobre
algumas metodologias famosas (Andrade, 2020).

10 PRINCIPAIS MÉTODOS ÁGEIS EXISTENTES

Primeiramente, listaremos os métodos ágeis famosos. O primeiro citado é


o Scrum (será explicado adiante), no Trello. Na década de 1990 vários modelos
influenciaram na criação de métodos ágeis. Podemos citar como exemplo os

36
seguintes modelos: Desenvolvimento Incremental, DSDM (Metodologia de
Desenvolvimento de Sistemas Dinâmicos), Crystal Clear, FDD (Desenvolvimento
Direcionado a Funcionalidade), XP (Extrem Programming) e Scrum. (Andrade,
2020).
O Quadro abaixo mostra a recomendação de métodos por fases do projeto
de desenvolvimento de software.

Fonte: Adaptado de Alegría et al. (2011)

O primeiro, desenvolvimento incremental, criado pela IBM em 1990, faz a


construção do sistema de pedaço em pedaço, ou de incremento em incremento.
Geralmente, um pedaço é feito, e após o cliente dá alguns feedbacks. Cada pedaço
é uma parte inteira: por exemplo, uma página de login link com acesso a banco de
dados é um incremento (SOMMERVILLE, 2011).
O segundo método cabível de explicação é a Metodologia de
Desenvolvimento de Sistemas Dinâmicos, o qual é usado em situações onde o
tempo e a verba são limitados. De acordo com Cruz (2018, p. 316) “[...] tem um

37
conceito mais próximo a um framework do que um método propriamente dito, sua
ênfase foca a criação de protótipos que posteriormente evoluem para o sistema, e
para isso é utilizada muito fortemente a colaboração próxima com o cliente”.
Este método buscar entregar 80% do projeto em 20% do tempo disponível.
Ele é composto por três fases: a fase do pré-projeto (onde se elabora o orçamento),
a fase do ciclo de vida (onde se analisa a viabilidade) e a fase do pós-projeto (onde
ocorrem as alterações), conforme a Figura abaixo:

Fonte: Adaptado de Alegría et al. (2011)

A Metodologia de Desenvolvimento de Sistemas Dinâmicos é recomendada


quando os projetos são urgentes, quando os projetos são formados por uma nova
tecnologia e precisam ser acompanhados de testes do usuário, ou quando remetem
a um lançamento de produto com data marcada. Qual é a diferença entre este
método e outros? Em metodologias tradicionais, como por exemplo, o famoso
Project Management Institute (PMI), o cronograma e o orçamento são abertos, e o
escopo é fechado; já a Metodologia de Desenvolvimento de Sistemas Dinâmicos

38
tem cronograma e orçamento fechados, mas o roteiro é aberto (SOMMERVILE,
2011).
O Crystal Clear (ISOTANI; ROCHA, [20––]) é outra metodologia ágil. Ela
atende vários tipos de projetos e tem como valor a comunicação com o cliente, bem
como o relacionamento do desenvolvedor com o cliente, a fim de que possa captar
com facilidade suas expectativas. Este método evita a criação de ferramentas
complexas que não serão utilizadas, objetivando reduzir tempo e custo na entrega.
Este método busca diferenciar a metodologia específica conforme a natureza de
cada projeto e permite que os desenvolvedores se manifestem quando algo os
incomodar. O método Crystal é um cristal em figura elaborado pela gestão e
mostrado com uma escala de cores, onde as cores variam de acordo com nível de
criticidade e com o tamanho da equipe: quanto mais escuro o cristal, mais crítico de
fazer é o software ou projeto; já as cores claras (branco e amarelo) atestam que os
software ou projetos serão simples e poucas pessoas serão necessárias; projetos
alaranjados ou até vermelhos demandam mais pessoas e são mais arriscados. No
Crystal da Figura 3, desenhado pela gestão, C significa confortável e D significa
baixo custo, E significa alto custo, e L significa risco de vida. O números indicam o
número de funcionários.

39
Fonte: Adaptada de Abrahamsson et al. (2002)

A metodologia Feature-driven development (FDD), ou “Desenvolvimento


Dirigido por Funcionalidades”, em português, fragmenta os projetos de gestão e de
software em features (funcionalidades). Ela foi concebida na década de 1990, e tem
como características os pontos, de acordo com Sommerville (2011):

• elaboração de lista de tarefas de funcionalidades, ou seja, cada


passo tem foco em alguma funcionalidade do software;
• planejamento voltado ao método incremental por funcionalidade, ou
seja, planeja-se etapas de acordo cada parte. Por exemplo: o
primeiro item a ser feito é a área do cliente completa; o segundo item

40
será o carrinho de compras completo; o terceiro item será o catálogo
completo, e assim por diante;
• design voltado à funcionalidade, ou seja, criar um design que
simplifica a navegação e promove a experiência do usuário;
• teste de software orientado à funcionalidade, ou seja, testar cada
função em detrimento de testar uma interface, por exemplo.

Pode-se perceber que neste projeto a soma de cada etapa se faz maior do
que o todo; assim, recomenda-se dividir em features curtas, a fim de agilizar a
conclusão de cada função, aumentando a eficiência da construção do programa.
Por exemplo: cria-se uma função de upload de imagens, cria-se uma função de
adicionar produto, e assim sucessivamente.
De acordo com Sommervile (2011), o quarto método a ser citado é o XP,
mais conhecido como Extremming Programing. Criado em 1996, possui como
princípios básicos: trabalho de qualidade, mudanças incrementais, feedback rápido
e abraçar mudanças. A metodologia possui algumas práticas:

• Jogos de planejamento: no início da semana os clientes e developers


(desenvolvedores) se reúnem parar priorizar funcionalidades que
serão entregues no final da semana. Cada versão deve ser pequena.
• Propriedade coletiva: qualquer pessoa do time pode usar o código
do programa sem precisar de permissão para alterar, assim todos
têm a oportunidade de conhecer o código inteiro e se familiarizar com
ele. Isso é muito importante para agilizar manutenções.
• Teste de usuário: em equipes pequenas são realizados testes do
software por clientes e desenvolvedores da empresa para avaliar sua
qualidade.
• Ritmo sustentável: as equipes devem trabalhar 40 horas, divididas
em 8 horas por dia, sem sobrecarga.

41
• Equipe inteira: as reuniões devem ser em pé e devem ser rápidas.
• Programação em par: um desenvolvedor mais experiente fica com
um novato, o novato codifica e o mais experiente programa. O
benefício deste método é que ele é revisado por duas pessoas.
• Padronizações de código: a equipe de dev (developers) determina
regras de codificação de salvamento, bem como as boas práticas
que devem ser seguidas. Assim, parecerá que foi a mesma pessoa
que editou o código, ele ficará com uma “cara” única.
• Desenvolvimento orientado a teste: elaborar códigos de forma que
sejam capazes de ser testados por software de teste como Imeter
(um software que mede desempenho), Selenium (um software que
mede erros de sites), etc.
• Refatoração: é o processo de otimizar a estrutura do código sem
alterar o seu comportamento externo para o usuário final.
• Integração contínua: integrar alterações de forma contínua, sem
esperar uma semana, por exemplo. Permite saber a real situação do
software da programação
• Entregas curtas: entregar pequenos pedaços para o cliente corrigir e
avaliar, aumentando a probabilidade de acertar o todo.
• Metáfora: entender a linguagem e as expressões do cliente.
• Design simples: o código deve ter exatamente o que o cliente pediu.

A quinta metodologia a ser citada é a Scrum. Ela também é citada por


Sommervile (2011). Não citaremos todas que existem, obviamente. Vamos abordar
alguns pontos sobre o Scrum (Andrade, 2020).

• Três pessoas principais devem ser citadas:

42
• o Product Owner, que define o que comporá o Product Backlog (lista
de ações do Sprint) e prioriza isso nas Sprint Planning Meetings
(reuniões de planejamento do Sprint);
• o Scrum Master (geralmente um gerente ou líder técnico), que
verifica se todos seguem as regras e também busca impedir
trabalhos excessivos;
• o Scrum Team é a equipe de desenvolvimento

No Scrum os projetos são divididos em etapas geralmente mensais. Pode-


se dizer que são ciclos mensais. Essas etapas chamam-se Sprints. Cada Sprint é
um Time Box, uma caixa no tempo com um conjunto de metas.
No Scrum existem reuniões diárias, chamadas Daily Scrum. Elas são feitas
no início do expediente e revisam os itens do dia anterior e determinam o que será
feito no dia.
As funcionalidades são agrupadas em uma lista. Product Backlog é esta
lista; ela contém todas as funcionalidades necessárias para um produto, e é feita
pelo Product Owner.
O Sprint Planning Meeting é uma reunião feita no início de cada Sprint.
Nesta reunião estarão presentes o Product Owner, o Scrum Master, o Scrum Team
e interessados. Nesta reunião o Product Owner determina as prioridades, e todos
juntos definirão um objetivo para aquele Sprint.
Este objetivo Sprint será revisado na Sprint Review Meeting, uma reunião
com o Product Owner, o Scrum Team, o Scrum Master, e algumas vezes com
gerência e clientes, a fim de revisar o que foi atingido e o que não foi.
O Release Burndown Chart é uma análise de metas atingidas no final de
cada Sprint (iteração).

43
11 TEST-DRIVEN DEVELOPMENT

Dentre as etapas genéricas presentes nos métodos de desenvolvimento de


software trabalhados pela literatura, a etapa de testes sempre esteve presente.
Após a popularização dos métodos ágeis, uma forma de desenvolver com foco nos
testes emergiu: o test-driven development (TDD). Nesse método, o teste deixa de
ser etapa e passa a ser o elemento protagonista, guiando o desenvolvimento do
início ao fim do projeto e invertendo a lógica de programar e depois testar, pois o
teste passa a ser a primeira ação nas iterações (Ladeira, 2020).
Neste capítulo, você estudará sobre o TDD, um método de desenvolvimento
dirigido por testes, conhecendo seus conceitos e sua história. Você estará apto a
entender o processo de desenvolvimento de software com o TDD, bem como a
identificar os seus benefícios e as suas limitações (Ladeira, 2020).

11.1 SURGIMENTO DE UM MÉTODO DE DESENVOLVIMENTO DIRIGIDO POR


TESTES

O TDD, também chamado de “desenvolvimento guiado por testes”, é um


método ágil de desenvolvimento que concentra os esforços de desenvolvimento na
capacidade de projetar testes e elaborar até que o componente esteja
completamente codificado e todos os testes executem sem erro (PRESSMAN;
MAXIM, 2016). Nesta seção, você aprenderá um pouco sobre a história deste
método, e compreenderá os conceitos centrais por ele utilizados (Ladeira, 2020).

44
11.2 HISTÓRICO

No ano de 2001, um grupo de desenvolvedores propôs mudanças nos


elementos essencialmente valorizados nos processos de desenvolvimento
tradicionais, o que culminou na elaboração do Manifesto para Desenvolvimento Ágil
de Software (BECK et al., 2001). Esse manifesto motivou a criação de diversos
métodos ditos ágeis, entre os quais estão Scrum, XP e outros. Um dos idealizadores
do manifesto foi Kent Beck, um engenheiro de software estadunidense que já
trabalhava em uma iniciativa de método ágil chamada extreme programming
(conhecido pela sigla XP ou também por “programação extrema”, em tradução livre),
que veio a se popularizar (Ladeira, 2020).
O método XP sempre conteve o teste entre as suas práticas. No contexto
do XP, a prática estava descrita como test-first (teste antes). Com o passar do
tempo, Beck percebeu que tal prática poderia ser desmembrada do XP e utilizada
de forma isolada, configurando-se em um novo método de desenvolvimento. De
acordo com Prikladnicki, Willi e Milani (2014), Beck publicou um artigo em 2001
relatando a prática como sendo uma técnica de design, e não propriamente de
testes, e, em 2003, publicou um livro sobre esta técnica, passando a chamá-la de
test-driven development (Ladeira, 2020).
O interessante é que Beck não se considera o criador do TDD, mas sim o
seu redescobridor, pois alega que essa prática é muito antiga. Mas será que é
mesmo? Conforme Larman e Basili (2003), sim: a IBM, na década de 60, executou
um projeto para a NASA chamado Mercury. Neste projeto, foi utilizada a prática de
teste-antes para cada pequeno incremento desenvolvido (Ladeira, 2020).
O registro mais antigo, entretanto, é de McCracken (1957), que relata a
necessidade de se trabalhar com ciclos curtos iterativos e de se elaborar o que
chamava de casos de verificação antes do código a fim de evitar erros lógicos e
mal-entendidos. Assim, o primeiro a mencionar as práticas do TDD é Daniel

45
McCracken, mas Beck é o responsável por redescobrir a técnica e sistematizá-la,
além de ser um dos grandes responsáveis pela sua popularização (Ladeira, 2020).

11.3 CONCEITOS DO TEST-DRIVEN DEVELOPMENT

De acordo com Beck (2011 apud PRIKLADNICKI; WILLI; MILANI, 2014, p.


201), “desenvolvimento dirigido por testes é um conjunto de técnicas [...] que
encorajam design simples e suítes de teste que inspiram confiança”. Segundo
Pressman e Maxim (2016, p. 854), “[...] o TDD não é realmente uma nova tecnologia,
mas sim uma tendência que enfatiza o projeto de casos de teste antes da criação
do código-fonte”. Neste modelo o elemento central é o teste, um conjunto de ações
relacionadas a um diagnóstico. Um teste sempre pode passar, o que significa que
o resultado retornado é o resultado esperado, ou falhar, o que significa diferença
entre esses resultados (Ladeira, 2020).
O tipo de teste que é realizado em todas as unidades de código criadas é o
teste unitário. Neste teste todas as pequenas porções de códigos criadas são
testadas por meio da citada comparação entre o valor esperado e o valor retornado.
A menor unidade testável pode variar de paradigma para paradigma, podendo ser
um arquivo, uma classe, um método, uma função etc (Ladeira, 2020).
O modelo de desenvolvimento dirigido por testes realmente tem design
simples. Ele é modelado em três estados: vermelho, verde e refatorar. A Figura 1
resume o modelo visualmente. Nela podemos ver três círculos, cada um
representando um dos estados do TDD (Ladeira, 2020).

46
Fonte: Ladeira (2020)

A ação inicial no TDD, antes mesmo de iniciar a implementação do


componente, é a elaboração do teste automatizado. Este teste inevitavelmente
falhará, pois ainda não há código. O conceito de falha está atrelado ao estado
vermelho, o primeiro estado possível definido pelo método. O conceito de sucesso
é modelado pelo estado verde, obtido a partir do momento em que o desenvolvedor
ou a equipe de desenvolvimento implementa um código que passa pelo teste. Já o

47
conceito de refatoração é modelado pelo terceiro e último estado: refatorar. Mas o
que é refatoração ? (Ladeira, 2020).
A refatoração é um conjunto de ações de aprimoramento da estrutura
interna do componente. Estas ações envolvem (Ladeira, 2020).

• eliminação de redundâncias no código;


• renomeação dos identificadores dos elementos internos, atendendo
aos padrões exigidos pela equipe;
• uso de estruturas de dados mais eficientes;
• uso de soluções mais eficientes;
• uso de bibliotecas mais adequadas;
• melhoria no gerenciamento de recursos.

Após a refatoração, o ciclo é reiniciado com um teste automatizado que


falha.
Existe ainda outro conceito importante relativo aos testes: como garantir que
uma alteração em um código novo não interferiu negativamente em uma unidade já
criada — e testada — anteriormente? É equivocado pensar que uma unidade já
testada não pode apresentar erros em função de outra criada depois, já que é
normal existir interdependência entre os componentes criados. A técnica de testes
de regressão, no entanto, é a proposta de solução nestes casos. Como os testes
são automatizados e escritos antes dos códigos, tem-se o histórico de todos os
testes realizados anteriormente; assim, para garantir que novas unidades não
tenham inserido erros em unidades já criadas, basta realizar os testes
automatizados novamente (Ladeira, 2020).
A ação de elaborar testes automatizados faz com que a equipe ganhe
tempo. Afinal, é mais rápido realizar testes de forma automática do que exigir a ação
humana para interagir com o componente, além de possibilitar que um conjunto
grande de dados seja testado. Essa ação contribui para a confiabilidade do

48
componente, pois passar por um conjunto volumoso de testes automatizados
minimiza as chances de problemas futuros. Prikladnicki, Willi e Milani (2014)
complementam afirmando que o teste automatizado é composto por etapas de
preparação, exercício e verificação, e definem como fundamental que o teste seja
autocontido, isto é, não dependa de intervenção humana para decidir o resultado
Como o TDD preconiza a realização de testes que sejam automáticos, por
vezes é necessário simular comportamentos de outros componentes que interagem
com a unidade testada mas não estão disponíveis neste formato ou não são viáveis
de se utilizar por questões de, por exemplo, desempenho ou complexidade. Alguns
componentes nessas situações estão relacionados à elaboração de interfaces cujo
comportamento depende da forma de ação do usuário, de acesso a arquivos
externos, a sistemas de gerenciamento de banco de dados ou até mesmo à
transmissão de dados em uma rede de computadores. Nestes casos, para viabilizar
os testes, foi proposto o conceito de mocks. Os mocks, também chamados de fake
mocks, mock objects ou objetos de simulação, representam simulações dos
componentes necessários. Esses objetos tentam reproduzir os objetos reais que
por algum motivo não podem ser utilizados nos testes (Ladeira, 2020).
Entre os motivos válidos para o uso de mocks estão, por exemplo, a
indisponibilidade do componente, seja por complexidade ou por ainda não estar
desenvolvido, ou até mesmo o desempenho do componente real, tal como um
sistema de gerenciamento de banco de dados cujas consultas sejam demoradas.
Assim, o uso de um objeto de simulação pode ser vantajoso por poupar tempo da
equipe de desenvolvimento e abstrair detalhes do componente (Ladeira, 2020).
A equipe de desenvolvimento pode elaborar seus próprios mocks ou utilizar
frameworks de suporte a mocks disponíveis para as principais linguagens de
programação do mercado (Ladeira, 2020).

49
11.4 O TEST-DRIVEN DEVELOPMENT NO CICLO DE VIDA DO SOFTWARE

Nesta seção analisaremos o TDD no ciclo de desenvolvimento de software


do ponto de vista de sua aplicabilidade. Discutiremos também a geração de
documentação para este método (Ladeira, 2020).
Pensemos agora na aplicabilidade do TDD por meio de um exemplo: uma
função que recebe um número natural (inteiro positivo) n entre 0 e 50 (inclusive) e
deve retornar o n-ésimo termo da Série de Fibonacci (Ladeira, 2020).
A Série de Fibonacci é uma sequência numérica na qual o primeiro valor é
o 0, o segundo é 1, e do terceiro valor em diante o elemento é sempre igual à soma
dos dois elementos anteriores. Os 10 primeiros elementos desta série são: 0, 1, 1,
2, 3, 5, 8, 13, 21 e 34. Você consegue identificar os elementos seguintes? (Ladeira,
2020).
O n-ésimo termo da Série de Fibonacci também é um número natural e,
portanto, a função recebe um número natural como parâmetro e retorna outro
número natural. Em uma pseudolinguagem de programação, a assinatura da função
seria como segue:

inteiro termoFibonacci(inteiro n)

Em um teste realizado com o parâmetro n = 7, qualquer resultado


retornado diferente de 8 resultará em um teste que falha, já que o valor esperado
para o sétimo termo de Fibonacci é 8. Se, por algum motivo, um teste com n = 7
resultar em valor diferente de 8 e o teste não falhar, o problema estará no caso de
teste projetado. Como o nosso método termoFibonacci seria testado utilizando a
abordagem do TDD? Inicialmente, precisaríamos escrever um teste, utilizando
nossa pseudolinguagem de programação (Ladeira, 2020).

50
testaTermoFibonacci() {
inteiro n = 10
inteiro resposta
inteiro respostaEsperada = 34
resposta = termoFibonacci(n)
escreva verificaIgualdade(respostaEsperada, resposta)
}

O teste demonstrado no exemplo é o teste unitário, sendo aplicado a uma


pequena porção testável (neste caso, o método termoFibonacci). O teste verifica
através do método verificaIgualdade se o valor retornado pelo método
termoFibonacci é igual ao valor da variável respostaEsperada (34, neste caso).
Por estarmos utilizando uma pseudolinguagem, considere que verificaIgualdade é
um método predefinido para comparação de valores. Os frameworks de testes
unitários costumam implementar este método com um nome semelhante a
assertEqual, mas há várias abordagens possíveis para escrever um teste unitário
(Ladeira, 2020).
As ferramentas de testes unitários criam seus métodos comparativos, mas
você pode elaborar testes sem depender destas ferramentas. Podemos elaborar
uma resposta diferente para o nosso exemplo da seguinte maneira:
lógico testaTermoFibonacci() { inteiro n = 10 inteiro respostaEsperada = 34
retorna (respostaEsperada == termoFibonacci(n)) } Neste exemplo, o retorno de
testaTermoFibonacci é um valor lógico (verdadeiro ou falso) que deve ser
manipulado ou apresentado no trecho de código que invoca o método. Este retorno
faz justamente a comparação de igualdade entre a resposta esperada e a resposta

51
calculada, retornando este valor. Note que aqui não foi utilizada a variável resposta,
mas o resultado é igualmente válido (Ladeira, 2020).
Como não há implementação de termoFibonacci, o teste falha, pois é
necessário implementar o método. Suponha agora que o desenvolvedor, utilizando
recursividade (chamadas sucessivas da função a ela própria), implementou o
método termoFibonacci na nossa pseudolinguagem de programação:

inteiro termoFibonacci(inteiro n) {
se (n == 1) {
retorna 0
}

se (n == 2) {
retorna 1
}

retorna termoFibonacci(n-1) +
termoFibonacci (n-2)
}

Agora, ao executar o nosso teste, o estado atingido é o verde, pois temos


um código implementado que funciona para o nosso teste. Note que, se a entrada
for 1, ou seja, deseja-se o primeiro termo, a saída será zero, pois o primeiro valor
da série é zero. Se a entrada for dois, a saída será um, pois um é o segundo valor
da série. Se a entrada for três, cai-se no caso da recursão, chamando
termoFibonacci(3-1) e termoFibonacci(3-2), ou seja, chama-se recursivamente
novamente a função duas vezes, uma com o valor 2, outra com o valor 1, e soma-
se o resultado de ambas. Neste caso, 0 + 1 = 1, ou seja, o terceiro termo é também
o valor 1. Cabe citar que, em uma situação real, um conjunto de dados de teste mais

52
volumoso seria utilizado e testado de forma automatizada, não apenas um teste
com a entrada 10 (Ladeira, 2020).
O próximo estado previsto no TDD é refatorar. Para atingir esse estado é
necessário verificar a possibilidade de realizar melhorias internas no método
termoFibonacci. Isso é possível?
Entre várias ações possíveis, eliminar redundâncias e padronizar o código,
caso a empresa de desenvolvimento utilize algum padrão, são algumas das ações
necessárias. Não havendo a necessidade de realizar estas ações, precisamos
pensar na sequência de instruções do método. O primeiro teste realizado é sempre
a verificação se o número é um. No entanto, o comando de retorno deste teste só
será executado quando o valor de n for um. Para todos os outros números aceitos
na entrada, um dos testes de parada será n == 2. Por exemplo, ao chamar
termoFibonacci(2), o teste n == 1 resultará falso, mas o teste n == 2 resultará
verdadeiro. Assim, a simples inversão de ordem destas estruturas condicionais já
configura uma comparação a menos, representando uma pequena melhoria no
código:

inteiro termoFibonacci(inteiro n) {
se (n == 2) {
retorna 1

se (n == 1) {
retorna 0 }
}

retorna termoFibonacci(n-1) +
termoFibonacci(n-2)

53
}
(Ladeira, 2020).

Ainda assim, as diversas chamadas recursivas continuam sendo bastante


custosas, pois a função chama a si própria diversas vezes. Há ainda a possibilidade
de juntar os dois testes, economizando linhas de código:

inteiro termoFibonacci(inteiro n) {
se (n == 2 ou n == 1) {
retorna n-1
}

retorna termoFibonacci(n-1) +
termoFibonacci(n-2)
}

O código ficou pequeno, elegante e não conta com redundâncias, mas


ainda está custoso em termos de tempo e espaço (memória utilizada). Soluções
recursivas costumam utilizar muita memória e, conforme entradas grandes são
utilizadas (ou seja, os maiores valores válidos para n), o tempo de processamento
passa a ser maior. Em uma situação como essa, é necessário pensar em melhores
soluções para o consumo desses recursos. Neste caso a solução iterativa, embora
gere mais código, é a mais eficiente, pois acessa menos vezes a memória e utiliza
apenas a alocação de um vetor no início do código (Ladeira, 2020).

inteiro termoFibonacci(inteiro n) {
n=n–1

se (n == 0 ou n == 1) {

54
retorna n
}
inteiro acumulador[50]
acumulador [0] = 0
acumulador [1] = 1
inteiro índice

para (indice = 2; indice <= n; indice++) faça {


acumulador[indice] = acumulador[indice-1]
+ acumulador[indice-2]
}

return acum[n];
}
}

Agora, tem-se uma função de cálculo do n-ésimo termo de Fibonacci de


forma iterativa. Esta implementação utiliza um vetor de 50 posições, pois este será
o valor máximo para n. O índice do vetor de 50 posições inicia em zero, então, para
um vetor de n posições, o vetor deverá variar de 0 a n-1, por isso a primeira instrução
decrementa 1 unidade do valor de n. Com este vetor o espaço de memória
determinado para resolver a função já está alocado, diferentemente da solução
recursiva, que gera diversas chamadas à função de forma dinâmica. A função
recursiva, se implementada em uma linguagem de programação, pode ocasionar
erros de execução em função das diversas chamadas recursivas, necessitando de
mais espaço de memória do que o disponível, situação altamente indesejada e que
deve ser evitada no estado de refatoração previsto no TDD (Ladeira, 2020).

55
Podemos supor, ainda, que a empresa exige que existam comentários
dentro da função, facilitando assim o entendimento de quem precisar manter o
código. Esta ação também deve ser realizada na etapa de refatoração. Assim, o
código comentado fica como segue (Ladeira, 2020).

/* Função que recebe um valor n inteiro positivo e


retorna um valor inteiro positivo que representa o
n-ésimo termo da Série de Fibonacci */
inteiro termoFibonacci(inteiro n) {
/* Decrementa n em uma unidade para
trabalhar com as posições corretas do vetor,
de 0 até n-1, resultando em n posições */
n=n–1
/* Como os dois primeiros valores são
conhecidos, retorna-se 0, se n for igual a zero, e
1, se n for igual a 1 */
se (n == 0 ou n == 1) {
retorna n
}

/* Declaração do vetor de tamanho 50, a maior


entrada possível neste caso */
inteiro acumulador[50]

/* Atribui às duas primeiras posições do


vetor os dois valores iniciais da Série de
Fibonacci. O primeiro elemento recebe o valor zero
e o segundo elemento recebe o valor um */
acumulador [0] = 0

56
acumulador [0] = 0

/* Declara o indice para percorrer o vetor */


inteiro índice

/* Percorre o vetor a partir da posição 2


(a terceira posição), preenchendo todos os valores
com a soma dos dois anteriores, conforme manda a
definição da Série de Fibonacci */
para (indice = 2; indice <= n; indice++) faça
{
acumulador[indice] =
acumulador[indice-1] + acumulador[indice-2]
}
/* Retorna o último valor do vetor, que será
o n-ésimo termo da Série de Fibonacci */
return acum[n];
}

Notou a diferença? O código, agora iterativo, está mais eficiente em


consumo de recursos e dentro do padrão (hipotético) de comentário da empresa
(Ladeira, 2020).
Após concluída a etapa de refatoração, o componente é entregue ou
incrementado com base em novos testes, que inicialmente falham, e assim inicia-
se o ciclo novamente. No nosso exemplo poderia haver a necessidade de mais um
incremento na unidade, exigindo também a implementação do método
fibonacciAteN, para imprimir todos os números da Série de Fibonacci até o n-ésimo
termo, passado como parâmetro (Ladeira, 2020).

57
Um aspecto importante que podemos discutir é a ausência de qualquer
diretriz sobre os requisitos. Assume-se que o desenvolvedor compreendeu
corretamente os requisitos necessários para desenvolver a funcionalidade. Isto se
materializará diretamente nos códigos dos casos de teste. No entanto, nada o
impede de, antes, modelar os requisitos com outra técnica, tal como a criação de
histórias de usuário ou casos de uso (Ladeira, 2020).
Vimos o exemplo da função termoFibonacci em um pseudocódigo
estruturado válido. Agora vejamos como isso seria feito em uma linguagem de
programação, em uma situação prática real. Tomemos como exemplo a linguagem
C++, utilizando-a também de forma estruturada para facilitar o seu entendimento,
juntamente com o compilador g++. O código de teste seria como segue (Ladeira,
2020).

#include <iostream>
#include "fi bo.h"

using namespace std;


int main() {
long long int respostaEsperada = 34;
long long int n;
long long int resposta;

n = 10;
resposta = termoFibonacci(n);
if (resposta == respostaEsperada)
cout << "Passou no teste!" << endl;

else
cout << "Falhou no teste!" << endl;

58
cout << "Entrada informada: " << resposta <<
endl;
cout << "Resposta informada: " << resposta <<
endl;
cout << "Resposta esperada: " << respostaEsperada << endl;
return 0;
}

Nosso código de teste resolve o mesmo problema que o código que


construímos na pseudolinguagem, mas note que ele tem algumas diferenças. Ele
verifica a resposta obtida e a resposta informada. Se forem iguais, informa que
passou no teste; se forem diferentes, informa que o teste falhou. Depois disso, a
entrada e as respostas informada e esperada são impressas na tela. Esta é uma
boa prática, pois assim o arquivo de saída registra mais informações do teste, não
somente “verdadeiro” ou “falso”. Outra diferença é o uso do tipo long long int, para
valores grandes. Por uma limitação de arquitetura, o tipo inteiro (int, em C++) não
seria capaz de receber valores grandes, como ocorre, por exemplo, quando n é 50
(Ladeira, 2020).
Agora, para poder sair do estado vermelho, nosso código precisa funcionar.
Para poder desenvolvê-lo, já incluímos o arquivo fibo.h, portanto devemos criar este
arquivo e acrescentar a assinatura da função desenvolvida nele (Ladeira, 2020).

long long int termoFibonacci(long long int n);

Agora, criamos o nosso código recursivo para passar no teste, no arquivo

fibo.cpp:

59
long long int termoFibonacci(long long int n) {
if (n == 2 || n == 1)
return n - 1;

return termoFibonacci(n-1) +
termoFibonacci(n-2);
}

Para executar e compilar o código, você pode utilizar o comando abaixo:

g++ testaTermosFibonacci.cpp fibo.cpp -o fibo; ./fibo

A resposta obtida deve ser:

Passou no teste!
Entrada informada: 34
Resposta informada: 34
Resposta esperada: 34

Assim, como o código funciona, estamos no estado verde. No entanto,


como já vimos, você pode tentar trocar o valor e executar para n = 50 para ver o
tempo e a memória sendo consumidos. Para isso, devemos refatorar o código
conforme realizamos no pseudocódigo. O nosso arquivo fibo.cpp deve ser refeito,
tal como o código abaixo (Ladeira, 2020).

/* Função que recebe um valor n inteiro positivo e


retorna um valor inteiro positivo que representa o
n-ésimo termo da Série de Fibonacci */

60
long long int termoFibonacci(long long int n) {
/* Decrementa n em uma unidade para trabalhar
com as posições corretas do vetor, de 0 até n-1,
resultando em n posições */
n--;

/* Como os dois primeiros valores são


conhecidos, retorna-se 0, se n for igual a zero,
e 1, se n for igual a 1 */
if (n == 0 || n == 1)
return n;

/* Declaração do vetor de tamanho 50, a maior


entrada possível neste caso */
long long int acumulador[50];

/* Atribui às duas primeiras posições do


vetor os dois valores iniciais da Série de
Fibonacci. O primeiro elemento recebe o valor zero
e o segundo elemento recebe o valor um */
acumulador[0] = 0;
acumulador[1] = 1;

/* Declara o indice para percorrer o vetor*/


int indice;

/* Percorre o vetor a partir da posição 2


(a terceira posição), preenchendo todos os valores
com a soma dos dois anteriores, conforme manda a

61
definição da Série de Fibonacci */
for(indice = 2; indice <= n; indice++)
acumulador[indice] = acumulador
[indice-1] + acumulador[indice-2];

/* Retorna o último valor do vetor, que será


o n-ésimo termo da Série de Fibonacci */
return acumulador[n];
}

Novamente, ao compilar e executar o código, a resposta obtida deve ser:

Passou no teste!
Entrada informada: 34
Resposta informada: 34
Resposta esperada: 34

Desta forma, conseguimos transcrever para uma linguagem de


programação o pseudocódigo inicial, realizando testes automáticos e melhorando a
implementação inicial da função termoFibonacci (Ladeira, 2020).

11.5 DOCUMENTAÇÃO

Até este ponto da leitura você pode estar se perguntando se (ou quando) o
TDD prevê a elaboração de documentação. A resposta a esta pergunta é mais
simples do que parece: a documentação já está elaborada! No TDD a
documentação é todo conjunto de testes implementados, pois eles mostram a
definição do comportamento esperado pelos componentes, sua interface e os tipos

62
dos dados definidos. Testes unitários, quando bem escritos, podem especificar o
trabalho do código funcional (Ladeira, 2020).
Por menor que seja o software desenvolvido, se a prática adotada for o
TDD, os testes devem permanecer armazenados, até mesmo porque estes testes,
enquanto documentos, são trabalhados em todos os estados do TDD. Além disso,
os testes realizados apoiam os futuros testes de regressão. Lembre-se de que um
software se diferencia de um programa por conter dados de configuração e
documentação. Portanto, a documentação é parte do software (Ladeira, 2020).
No caso do código apresentado, os arquivos que implementam o método
de teste (testaTermoFibonacci) fazem parte da suíte de testes, bem como fariam os
métodos que testam os métodos de subtração e de outras operações, se for o caso
do software em desenvolvimento. Se, futuramente, por algum motivo, o método de
teste precisar de correções ou alterações em virtude de mudanças de requisitos,
mantém-se o arquivo anterior e cria-se o novo. Todos os arquivos de teste gerados
formam a suíte de testes e ajudam a compreender o histórico de desenvolvimento
do software (Ladeira, 2020).

12 VANTAGENS E DESVANTAGENS DO TEST-DRIVEN DEVELOPMENT

Todo método de desenvolvimento de software tem suas especificidades.


Alguns podem ser mais vantajosos em determinadas situações, outros podem
apresentar limitações. O profissional que lidera as decisões da equipe de
desenvolvimento de software deve estar ciente das características dos métodos,
pois esta escolha é vital para o andamento do trabalho (Ladeira, 2020).

63
12.1 VANTAGENS DA UTILIZAÇÃO DO TEST-DRIVEN DEVELOPMENT

Como você pode analisar na leitura do capítulo, uma das principais


características do TDD é a simplicidade. Este método apresenta transições de
estado bem definidas, não ambíguas e em pouca quantidade, pois são apenas três.
Além disso, a simplicidade também fica evidenciada na elaboração de artefatos,
pois a documentação da equipe se resume aos casos de teste (Ladeira, 2020).
O TDD é fácil de ser absorvido pela equipe de desenvolvimento graças à
simplicidade; como consequência, traz também um outro benefício: o tempo
necessário para o treinamento da equipe para a adoção do método no ciclo de vida
do software. Assim, a equipe que opta por utilizar o TDD não despende grande
quantidade de tempo para aprendê-lo — e tempo é um fator crítico no
desenvolvimento de software (Ladeira, 2020).
O suporte de ferramentas também é um ponto positivo do TDD. Há
diversos software para automatização de testes e realização de testes unitários
disponíveis, bem como frameworks e bibliotecas para criação de mocks. Essas
ferramentas ajudam a prática de desenvolver guiado por testes e aceleram o
desenvolvimento (Ladeira, 2020).
As características citadas ajudam os desenvolvedores a serem ágeis e
produtivos, já que o esforço é concentrado em atividades bem definidas, simples e
de feedback rápido. Além disso, incentivar a elaboração de testes automatizados
também contribui para a produtividade, pois exige menos ação humana nesta etapa
(Ladeira, 2020).
Apesar de simples, o TDD impede que a equipe deixe de lado a qualidade
do produto desenvolvido; pelo contrário, ele prevê a etapa de refatoração, na qual
deve-se atentar para otimização, padronização e limpeza do código. Isto também
encoraja a equipe de desenvolvimento a pensar melhor no projeto do componente,
aumentando sua coesão e procurando diminuir a dependência de outros módulos
(Ladeira, 2020).

64
Já que o código é sempre coberto por testes que são documentados, os
desenvolvedores também adquirem maior confiança sobre os códigos
desenvolvidos. Neste ponto, os testes de regressão contribuem muito, já que o
registro e a reexecução dos testes anteriores ajuda a não permitir que a elaboração
de componentes gere erros em outros componentes, sendo este caminho rastreável
na sua totalidade (Ladeira, 2020).
O uso do TDD também acaba incentivando a testabilidade do código; isto
é, o desenvolvedor pensa o seu código de forma que ele seja fácil de testar. Se o
componente tem baixa testabilidade, estará mais propenso a esconder as falhas e
poderá produzir defeitos (Ladeira, 2020).
O TDD favorece ainda a flexibilidade. A agilidade do método, advinda do
seu ciclo curto de estados, permite adaptação ágil a novos requisitos e eventuais
alterações no código. É possível ainda que você, enquanto desenvolvedor, avalie e
utilize somente as práticas que julga interessantes no TDD ou proponha
customizações no processo que você entenda serem positivas na sua realidade de
trabalho (Ladeira, 2020).

12.2 DESVANTAGENS DA UTILIZAÇÃO DO TEST-DRIVEN DEVELOPMENT

Apesar de apresentar diversas vantagens, o método TDD também tem suas


limitações. A testagem excessiva é considerada, em alguns casos, uma
desvantagem. Em módulos de pouca complexidade a equipe de desenvolvimento
acaba trabalhando mais tempo na criação do teste automatizado do que na unidade
a ser desenvolvida. Outra desvantagem reside no fato de que o tempo necessário
para desenvolver uma funcionalidade se torna cada vez maior, pois é necessário
aplicar os testes (de regressão) nas unidades anteriores que se relacionam com a
unidade recém-criada (Ladeira, 2020).

65
O uso da suíte de testes como única documentação também é vista como
negativa por alguns autores que entendem que os casos de teste não foram criados
para serem toda documentação de software, e que outros documentos poderiam
auxiliar nas etapas de manutenção (ANWER et al., 2017).
Outro ponto a ser discutido é a limitação que o uso de mocks impõe. É difícil
testar a integração real com outros componentes, tais como sistemas de
gerenciamento de banco de dados ou interfaces de usuário, e é também difícil
garantir que o objeto simulado terá comportamento idêntico ao componente. Este
ponto é especialmente crítico em situações em que os objetos sofrem alterações
contínuas ou se os objetos em questão forem mantidos por terceiros (Ladeira,
2020).
O modelo não prevê a refatoração dos casos de teste. Isso significa que, se
os desenvolvedores não perceberem, um teste mal elaborado (com erros ou
incompleto, por exemplo) pode ser executado e fornecer a falsa sensação de
corretude. Um teste mal projetado pode ser identificado somente na fase de
manutenção, o que não é desejável e resulta em retrabalho. Além dos casos de
projeto incorreto de casos de teste, há situações em que há cenários de incerteza
e de necessidade de alteração de requisitos. Nestes casos o TDD também pode ser
desvantajoso, pois mudanças no projeto podem exigir que os testes sejam refeitos,
gerando perda no tempo de desenvolvimento (Ladeira, 2020).
Devido à lógica do TDD (escrever o teste antes do código), é um método
difícil de ser aplicado em ambientes em que existam códigos legados. Conforme
Anwer et al. (2017), o TDD também não se aplica a projetos de software que
requerem sincronização.
Anwer et al. (2017) afirmam também que o TDD é um método incompleto.
Segundo eles, o TDD não fornece orientações sobre como gerenciar projetos de
software desenvolvidos com este método, que se concentra apenas em atividades
relacionadas à engenharia.

66
Ainda há muita desinformação sobre o TDD. Ele muitas vezes é confundido
com a prática de testes unitários ou de automatização de testes, práticas estas que
na verdade são englobadas pelo TDD (Ladeira, 2020).

67
13 REFERÊNCIAS BIBLIOGRÁFICAS

IEEE Std-830. IEEE Recommended Practice for Software Requirements


Specifications. IEEE, 1998.

KOTONYA, G.; SOMMERVILLE, I. Requirements engineering:


processes and techniques. Chichester: John Wiley, 1998.

SOMMERVILLE, I. Software engineering. 9th ed. São Paulo: Pearson


Prentice Hall, 2011.

THE STANDISH GROUP. The chaos report. 1994. Disponivel em:


<https://www.csus. edu/indiv/v/velianitis/161/chaosreport.pdf>. Acesso em: 01 jul.
2018.

ALEXANDER, C. et al. Uma linguagem de padrões. Porto Alegre:


Bookman, 2012.

FOWLER, M. Padrões de arquitetura de aplicações corporativas. Porto


Alegre: Bookman, 2007.

HORSTMANN, C. Padrões e projetos orientados a objetos. 2. ed. Porto


Alegre: Bookman, 2007.

LARMAN, C. Utilizando UML e padrões: uma introdução à análise e ao


projeto orientado a objetos e ao desenvolvimento iterativo. 3. ed. Porto Alegre:
Bookman, 2007.

METSKER, S. J. Padrões de projeto em Java. Porto Alegre: Bookman,


2004.

PRESSMAN, R. S.; MAXIM, B. R. Engenharia de software: uma


abordagem profissional. 8. ed. Porto Alegre: AMGH, 2016.

68
SHALLOWY, A. Explicando padrões de projeto: uma nova perspectiva
em projeto orientado a objetos. Porto Alegre: Bookman, 2004.

ABRAHAMSSON, P. et al. Agile software development methods: review


and analysis. Espoo: VTT, 2002.

ALEGRÍA, J. H. A. et al. An MDE approach to software process tailoring.


In: INTERNATIONAL CONFERENCE ON SOFTWARE AND SYSTEMS PROCESS,
2011, Honolulu. Proceedings […]. New York: ACM, 2011. p. 43–52.

AMARAL, D. C. et al. Gerenciamento ágil de projetos: aplicação em


produtos inovadores. São Paulo: Saraiva, 2012.

ATLASSIAN. Jira sotware: planos e preços. c2020. Disponível em:


https://www.atlassian. com/br/software/jira/pricing. Acesso em: 15 jun. 2020.

BECK, K. et al. Manifesto para desenvolvimento Ágil de software.


c2001. disponível em: https://agilemanifesto.org/iso/ptbr/manifesto.html. Acesso
em: 15 jun. 2020.

CRUZ, F. Scrum e Agile em projetos: guia completo. 2. ed. Rio de


Janeiro: Brasport, 2018.

ISOTANI, S.; ROCHA, R. V. Desenvolvimento Ágil. [20––]. Disponível em:


https://edisciplinas.usp.br/pluginfile.php/3128670/mod_resource/content/1/Aula04_
Desenvolvimento_agil_Rafaela.pdf. Acesso em: 15 jun. 2020.

MARTIN, R. C. The clean coder: a code of conduct for professional


programmers. Upper Saddle River: Prentice Hall, 2011.

SOMMERVILLE, I. Engenharia de software. 9. ed. São Paulo: Pearson


Prentice-Hall, 2011.

69
ANWER, F. et al. Agile software development models TDD, FDD, DSDM,
and crystal methods: a survey. IJMSE, v. 8, n. 2, p. 1–10, 2017. Disponível em:
http://www.ijmse.org/ Volume8/Issue2/paper1.pdf. Acesso em: 23 maio 2020.

BECK, K. et al. Manifesto para desenvolvimento ágil de software. [S. l.:


s. n.], 2001. Disponível em: https://agilemanifesto.org/iso/ptbr/manifesto.html.
Acesso em: 23 maio 2020.

LARMAN, C.; BASILI, V. R. Iterative and incremental development: a


brief history. Computer, v. 36, n. 6, p. 47–56, 2003. Disponível em:
https://www.craiglarman.com/wiki/ downloads/misc/history-of-iterative-larman-and-
basili-ieee-computer.pdf. Acesso em: 23 maio 2020.

MCCRACKEN, D. D. Digital computer programming. New York: John


Wiley & Sons, 1957.

PRESSMAN, R. S.; MAXIM, B. R. Engenharia de software: uma


abordagem profissional. 8. ed. Porto Alegre: AMGH, 2016.

PRIKLADNICKI, R.; WILLI, R.; MILANI, F. Métodos ágeis para


desenvolvimento de software. Porto Alegre: Bookman, 2014.

70

Você também pode gostar