A raiz de todos os medos

A raiz de todos os medos: "
Todas as profissões envolvem algum tipo de responsabilidade. Toda a responsabilidade envolve algum tipo de risco. Gerenciar o risco corretamente é que torna a pessoa um profissional.

Em desenvolvimento de software existem diversos riscos associados ao projeto, mas vamos focar hoje nos riscos associados ao código.

A qualidade do código é proporcional ao quão limpo ele esta. Manter a qualidade do software é a principal forma de minimizar o risco.

Num desenvolvimento desatento presume-se que a única função do código é prover a funcionalidade requerida nos requisitos funcionais. O velho e bom “Está funcionando”. Este tipo de desenvolvimento é tão comum que gerou a máxima “Primeiro faz funcionar, depois faz funcionar bem. Depois faz funcionar rápido.” Este tipo de pensamento pode funcionar no meio acadêmico quando vocês está descobrindo um algoritmo novo, contudo fora do mundo acadêmico esse pensamento é uma anti-regra. Ele viola o mais fundamental propósito de qualquer empresa : lucro, ao obrigar a uma re-edição do software pelo menos 2 vezes.

Em código feito para compor produtos de software essa regra não pode ser seguida, contudo, sabemos que não é fácil acertar à primeira num bom modelo ou numa implementação performática. Ser capaz de alterar o software é um requisito constante e é a essência de toda a teoria por detrás de todos os paradigmas de programação (de orientado a instruções a orientado a objetos) : queremos nosso código fácil de mudar. Então porque não o mudamos mais frequentemente ?

A principal razão é o código ter sido escrito de forma confusa e suja ( não limpa). Código escrito assim viola o requisito constante de ser capaz de alterar o software facilmente. A grande maioria de desenvolvedores produz código assim e não é simples treinar uma pessoa a fazer de forma diferente.

A segunda razão é a escolha de modelo falhos ou falidos. Modelos falidos são aqueles que parecem resolver o problema e são tradicionalmente passados de boca em boca como solução para certo problema, mas com o passar do tempo ele não resistem. Formas de programação que eram considerar o topo da qualidade num paradigma, caem para anti-padrões em outro. Um exemplo simples; o modelo do Struts funcionou durante um tempo, mas é hoje um modelo falido.

Modelos falhos são aqueles que resolveram o problema num certo momento mas não resistem à adição da necessidade de mais funcionalidades. Um exemplo é a classe java.util.Date. Resolver o problema de trabalhar com datas durante um tempo, mas o modelo era fraco para abarcar todas as necessidades do contexto de datas. É um modelo falho.

Modelos podem ser compostos de várias classes ou poucas, não é relevante. O problema acontece quando detectamos que o modelo falhou ou faliu e precisamos remodelá-lo. Quem vai querer mexer naquele código legado escrito ha mais de 3 anos por um pessoa que não está mais na empresa ?

A primeira reação a esta situação é medo. Medo de alterar um código que está funcionando mas que precisa ser alterado, no todo ou em parte, de forma a que mantenha as funcionalidades atuais e novas sejam adicionadas. O medo advém da falta de controle sobre o estado de funcionamento do código.

Código limpo pode ajudar a entender melhor o código que está escrito, mas não o ajuda a verificar que após uma alteração ele ainda funciona como esperado. Precisamos de algo mais eficaz, mais dinâmico. Precisamos de testes.

A escrita de testes não é um luxo, é uma necessidade inerente à produção de código. Escrever testes para o seu código é equivalente a colocar mecanismos de segurança em centrais nucleares. Não podemos apenas confiar que nunca vai acontecer nenhum problema ou que nunca precisaremos de fazer alguma manutenção.

Porque a principal preocupação da maioria dos desenvolvedores é colocar o código a funcionar mas sem criar nenhuma forma de verificar que o código continua funcionando, os mesmos desenvolvedores são depois dominados pelo medo de mudar o código que eles mesmos escreveram.

A escrita de código que verifica a consistência das funcionalidades do código de produção é uma necessidade e não uma opção. A menos é claro que você esteja disposto a gastar rios de dinheiro e tempo em alterações arriscadas, ou se o seu software for durar 3 meses.

Como escrever esses testes e quais testes escrever ?

O relacionamento entre as operações necessárias num projeto de software e as respectivas áreas de teste apresentadas pelo V-model mostra que existem vários tipos de teste conforme o objetivo e o nível de certeza que queremos ter. Isto nos leva a 4 tipos de teste: Teste Unitário, Teste de Integração, Teste de Sistema e Teste de Aceitação.

O teste unitário verifica que a unidade de codificação está em conformidade. A unidade de codificação depende do paradigma de programação usado. Em Orientação a Objetos pode ser uma classe ou um pacote de classes. O teste de integração verifica o funcionamento de várias unidades de codificação trabalhando juntas está em conformidade. O teste de sistema, verifica que o sistema funciona em conformidade em diversos ambientes, com diversas niveis de carga, com diversos niveis de recursos ( memória, CPU, banco de dados, etc..) , em diversas configurações e distribuições em rede. O teste de aceitação verifica que o sistema atende os requisitos funcionais especificados para ele.

Existem outros tipos de teste como teste de mercado que determina como os usuários reagem ao sistema, como o utilizam, com que frequencia, etc. Este tipo de testes não faz parte do desenvolvimento do software e está mais ligado a como o software é aceite como um produto no mercado. Este tipo de testes não são cobertos aqui, mas também eles tendem a minimizar o medo e as falhas.

O cenário necessário é que todos os 4 tipos de teste sejam automatizados e verificados constantemente. Este é o conceito de Integração Continua. Embora o nome remeta aos testes de integração, todos os 4 tipos de teste podem ser avaliados continuamente.

A correção de um defeito nos requisitos funcionais é muito mais caro que um defeito na unidade de codificação. Por esta razão os testes de aceitação devem ser escritos primeiro para testar se o requisito realmente atende o usuário. No inicio a codificação necessária ao funcionamento desse requisito é simulada com valores fixo para permitir que o requisito em si mesmo seja validado. Coisas como navegação, regras de validação de dados e outros tipos de input, são também validados por estes testes. Lembrar que estes testes são automatizados e executados continuamente. Se o requisito mudar , o teste terá que mudar em conformidade.

Os desenvolvedores partem então para a escrita do código real que irá prover aquelas funcionalidades. Na medida em que esse código é escrito também os seus respectivos testes de integração e unidade são escritos. Estes testes garantem que o código funciona, e os testes de aceitação garantem que este funcionamento está em conformidade com os requisitos funcionais.

Contudo, todo o sistema conta com requisitos não funcionais que devem também ser atendidos pelo software. Para testar estes, testes de sistema são incluídos. Estes testes completam os outros 3 garantido que o código está em conformidade com os que os usuários esperam tanto do ponto de vista do objetivo do software, como do ponto de vista da usabilidade, instalação, manutenção, atualização, etc…

Entenda-se que dado um conjunto de testes para um software é sempre possível criar mais testes que completem esse conjunto. em teoria este crescimento não tem limite. Na prática ele tem que ser limitado pelo grau de confiança que precisamos do software. Algumas métricas como a cobertura ( numero de linhas de código executas durante os testes) podem ajudar a definir esses graus de confiança, ou testes específicos podem ser desenhados para medir esse grau.

A raiz de todos os medos que os desenvolvedores sentem face a um código que não escreveram, o que não lembram que escreveram é a falta de mecanismos automáticos de verificação da continuidade da consistência da funcionalidades.

A adição de testes automatizados é uma necessidade do desenvolvimento de software, é um “osso do oficio” e não uma opção, embora possamos argumentar que a profundidade e tipo dos testes está relacionada a variáveis como o tempo espectável para a vida do software, a facilidade em atualizar o comigo depois de instalado (impossível num software que controla uma sonda espacial, por exemplo) e o nível de risco associado à falha do software (elevado em software de que depende a vida de alguém). Estas variáveis alteram o pormenor associado à escrita e detalhe dos testes e não o fato deles serem necessários.

Agora pense: quão apavorado você fica de mexer no código do seu projeto atual ?



creditar conteúdo
"

Comentários

Postagens mais visitadas