DevSecOps

5 jul, 2016

Os pilares da qualidade de software e como garanti-los

Publicidade

Menos subjetiva do que parece, a manutenção da qualidade de software em projetos digitais jamais deve ser tratada como opcional.

A qualidade sempre foi ponto decisivo na escolha feita por qualquer consumidor sobre as suas compras – algo válido para objetos, comida e até serviços. É isso que, por exemplo, nos faz optar por produtos mais duráveis, ou roupas com um acabamento mais sofisticado, mesmo que seu preço seja maior. É também o que faz sua avó falar com orgulho do aspirador que ela comprou antes de você nascer e “olha só, minha filha, funciona muito melhor do que essas porcarias que a gente compra hoje em dia”. Ou seja, ainda que o conceito de qualidade possa ser subjetivo, ele é um dos principais elementos a agregar valor a um produto.

Atualmente, softwares movem partes importantes das nossas vidas. De máquinas de lavar a carros, passando por, claro, smartphones e computadores, são incontáveis os objetos, as máquinas e até os veículos que hoje dependem de milhares de linhas de código para o seu funcionamento. Não à toa, algumas das maiores companhias do mundo, como Google e Apple, são também gigantes do software, responsáveis por muitos dos aplicativos e sistemas que compõem o nosso dia a dia.

Nesse contexto, como medir, então, a qualidade de um software? Que elementos são capazes de indicar que um software possui ou não qualidade? Será que qualidade de software se resume à qualidade do código por trás dele? Como traduzir isso em métricas?

Ao contrário do que muitos podem supor, o processo de produção de um software em nada se parece com aquele linear de uma linha de montagem industrial, por exemplo, onde o controle de qualidade visa minimizar defeitos e técnicas similares podem ser empregadas em todas as fases do processo. Questões como clientes indecisos, requisitos mal especificados, prazos apertados, linhas de código mágicas e testes “vagalumes” não são novidade para nenhum programador experiente, e medidas que se adaptem a demandas específicas de cada projeto são mais do que necessárias.

Assim, para que possamos descobrir o que realmente significa qualidade de software, é preciso pensar em todo o seu processo de desenvolvimento: da concepção do produto, passando pela fase de implementação, até chegarmos no software final. Não só isso, é necessário ainda considerar os atores envolvidos em cada etapa e o papel que desempenham, sejam eles clientes, desenvolvedores ou usuários.

Dito isso, com base na experiência desenvolvida em projetos de diferentes escopos na Huge, observo que podemos, então, avaliar a qualidade de um software por três perspectivas ligadas a cada etapa do seu desenvolvimento: qualidade funcional, qualidade estrutural e qualidade de processo.

A qualidade funcional

Consiste na eficiência do código, no quão bem a aplicação cumpre o seu papel. Esse aspecto é extremamente importante, principalmente para os usuários, que são os maiores afetados pela performance e confiabilidade do sistema.

Para que um software seja considerado funcionalmente bom, é essencial que ele cumpra com os requisitos especificados pelo cliente, em todas as suas fases de implementação. Não só isso, mas que também seja confiável, com uma quantidade menor possível de bugs. E, finalmente, que tenha uma boa performance e uma interface intuitiva. Afinal, se a interface não for boa o suficiente, não importa que o seu código seja o mais modularizado e limpo do mundo – seu produto ainda não será utilizável.

E como alcançar uma boa qualidade funcional de software? Há alguns recursos e ferramentas que podem ser utilizados para esse fim:

  • Testes unitários, de integração e de aceitação dão ao desenvolvedor um panorama em tempo real do estado da sua aplicação, tornando o seu código muito mais confiável, principalmente se estiverem integrados a uma plataforma de integração contínua, possibilitando uma pipeline de entrega totalmente automatizada;
  • Outro recurso importante são os testes de carga (load testing), que basicamente disparam uma quantidade elevada de requisições ao sistema e monitoram como o mesmo se comporta. Trata-se de um recurso útil para traçar estratégias para um fluxo intenso de dados, como subir múltiplos servidores para a sua aplicação e deixar alguns de fallback, caso o seu servidor principal não suporte a quantidade massiva de requisições simultâneas.Um framework muito interessante de load testing é o Locust, onde você pode definir exatamente o comportamento de usuário desejado por meio de poucas linhas de código em Python. Uma das principais vantagens desse framework é o fato dele operar de forma completamente distribuída, sendo capaz de simular milhões de usuários simultâneos a partir de servidores em diferentes localidades.
  • Por último, mas não menos importante, estão os testes de segurança (security testing). Eles permitem a identificação de brechas de segurança que podem por ventura existir no sistema e emitem um relatório completo mapeando essas falhas, e até sugerindo medidas adequadas a cada um dos problemas detectados.
  • Para isso, um dos frameworks mais utilizados atualmente é o Zed Attack Proxy, ou ZAProxy, para os íntimos. É possível usá-lo como plugin no Jenkins, integrá-lo de forma extremamente simples à sua pipeline de deploy e obter, automaticamente, um relatório detalhado de todas as brechas de segurança da aplicação.

Qualidade estrutural

É a qualidade do código escrito e o quão bem estruturado ele é. Pontos como modularização e re-usabilidade são essenciais nesse aspecto para garantir que o código é de fácil compreensão e manutenível – ou seja, possa ser incrementado com novas features sem que estas “quebrem” suas funções. Nesse parâmetro, os desenvolvedores são o “público alvo”, já que a legibilidade e a escalabilidade do código influenciam diretamente na ambientação de novos profissionais no projeto e, consequentemente, na velocidade de implementação.

Para garantir esta qualidade, é necessário ainda que o código seja testável e tenha funções atômicas: ou seja, limpas, claras e cumpram com um propósito específico. Sem um código testável, não é possível escrever os testes automatizados mencionados anteriormente e, assim, pode-se comprometer a qualidade funcional do software – uma coisa puxa a outra.

Outro ponto a ser levado em consideração nesse quesito é a legibilidade do código: que ele tenha funções e variáveis simples e explícitas. Isso facilita a compreensão e a assimilação do código por novos desenvolvedores, acelerando a implementação de novas features. Afinal, ninguém gosta de passar pelo desespero de ter que procurar por bugs em um código onde as variáveis se chamam “a”, “b”, “c”, “rinoceronte” e “banana”, e ações inesperadas acontecem a todo momento. Assim, para que não haja perda de performance e confiabilidade na utilização da aplicação, é essencial que o código seja eficiente, seguro e escalável.

Mas, e agora? Quem poderá nos defender? Isso mesmo que você está pensando (ou deveria): uma boa análise de complexidade com plato.js, linters e muita, muita, muita refatoração certamente serão úteis nessa jornada em busca da qualidade estrutural.

Qualidade de processo

Essa última perspectiva consiste na adoção de técnicas e estratégias que tornem o processo de implementação do produto o mais equilibrado possível. Nesse aspecto, clientes e participantes do projeto são os mais afetados, justamente pelo fato de que essa qualidade tem um impacto direto nos prazos e requisitos do produto.

Uma preocupação redobrada com prazos de entrega e respeito ao orçamento, por exemplo, é essencial para que o cliente não se decepcione quanto ao desenvolvimento do projeto – cenário que pode gerar ruídos na comunicação entre as partes envolvidas. Para isso, as equipes de produção precisam estar em plena sintonia e o gerente de projeto deve estar ciente das necessidades e do ritmo de trabalho de programadores e designers para que possa negociar um prazo adequado para cada feature. Do contrário, é possível que haja uma perda na qualidade do código produzido por inadequação dos prazos estabelecidos para as features.

Por fim, o ponto chave da qualidade de processo é ter um processo de entrega consistente. É muito frequente que haja uma mudança na metodologia de desenvolvimento no meio do projeto, seja por problemas na organização das demandas do cliente, ou por prazos muitos apertados. Em todos os casos, o famoso scrumterfall(mistura do desenvolvimento Scrum com Waterfall) deve ser evitado: a mudança de paradigmas no curso da implementação do produto é extremamente nociva, podendo gerar estresses desnecessários para a equipe de desenvolvimento, que se vê tendo que mudar de estratégia de trabalho o tempo todo.

Métricas ágeis como gráficos de burndown e scrumboards são extremamente úteis nesse aspecto, pois auxiliam na visualização do ritmo de trabalho da equipe como um todo e, consequentemente, na estimativa de prazos mais próximos do ritmo de trabalho real. Medidas como retrospectivas e planejamento de sprints são bastante benéficas para um processo onde as vontades e expectativas do cliente, e de membros do projeto, são respeitadas e contribuem para uma rotina de trabalho mais saudável.

Conclusão: o novo mantra em desenvolvimento

Ao final desta reflexão, podemos concluir que não há um jeito único de definir qualidade de software. No entanto, a consideração desses três pilares – qualidades funcional, estrutural e de processo – enfatizam os maiores pontos de atenção e as estratégias que idealmente deveriam ser adotadas no decorrer do processo de desenvolvimento de software. Tentar encontrar um ponto de equilíbrio entre esses três aspectos é fundamental para a obtenção de um produto que satisfaça todos os stakeholders – clientes, usuários e desenvolvedores.

Ao observarmos a importância que o software assumiu em nossas vidas, é essencial que nós, desenvolvedores, comecemos a produzir aplicações de alto nível de performance e confiabilidade. Não é mais aceitável que tratemos qualidade de software como uma mera feature no meio de todas as demandas do projeto. Trabalhem pelo novo mantra: qualidade de software não é opcional.