Doze passos para se ter um código melhor (Parte 1)

Joel Spolsky é ex-funcionário da Microsoft, um dos fundadores do utilíssimo Stack Overflow e é, além disso, um evangelizador de boas práticas do processo de desenvolvimento de software e tópicos relacionados. No seu blog pessoal, ele mantém uma série de artigos que expõe sua opinião sobre o assunto, sendo vários deles bem conhecidos no meio e são considerados clássicos, sendo utilizados como referência por vários outros bloggers.

Um destes artigos é o The Joel Test: 12 Steps to better code, onde o autor propõe um teste com doze perguntas que serviriam para avaliar a qualidade de uma equipe de desenvolvimento de software. O artigo foi escrito há mais de 12 anos (que é uma eternidade no mundo de TI) e é interessante analisar se as preocupações do autor na época ainda são válidas e verificar o quanto avançamos de modo geral levando em consideração não apenas o tempo que o artigo foi escrito, mas as práticas ágeis de desenvolvimento difundidas hoje em dia.

Nesta primeira parte, iremos analisar as seis primeiras questões.

1 – Você (ou sua equipe) utiliza controle de versão?

Hoje é impossível acreditar que exista alguma empresa séria que desenvolva software e que não use um sistema de controle de versão. Nem mesmo para “equipes” de duas pessoas pode ser considerado viável deixar de utilizar um sistema de controle de versão. Existem várias soluções gratuitas e excelentes baseadas em Mercurial e Git, por exemplo, ou comerciais como o TFS. Mas nenhuma dessas soluções existiam quando Joel escreveu o artigo, nem mesmo o SVN. O sistema mais popular na época era o CVS, que ele inclusive cita no texto. Compartilhar código-fonte via rede ou outra solução semelhante leva ao caos absoluto pois exige extrema disciplina dos desenvolvedores de times de desenvolvimento. Sem um sistema de controle de versão a perda e a necessidade de reescrever código deviam ser problemas comuns.

O que se poderia perguntar hoje em dia é: Você/sua equipe utiliza o controle de versão de forma eficiente?  Realiza branches/merges quando necessário? Utiliza uma estrutura hierárquica organizada? Consegue rastrear as mudanças no código-fonte e associá-las a bugs ou tarefas? Utiliza uma solução centralizada ou distribuída?

2 – Você consegue gerar um build em um passo?

Você consegue gerar os binários de suas aplicações com apenas “um clique” a partir do código-fonte no sistema de controle de versão?  No caso de softwares “de prateleira”, os binários devem estar empacotados em  instaladores .EXE ou .MSI e no caso de websites ou plataformas, devem estar publicados em servidores de desenvolvimento ou staging. Esta pergunta, portanto, está relacionada à automatização do processo de construção do software.

No artigo, o autor sugere que a construção dos binários pode ser feita através de scripts que automatizem o processo. Hoje em dia, o mais comum é que hajam servidores dedicados para esta atividade, os chamados build servers. Estes servidores devem ser neutros (não utilizados por desenvolvedores) e além de gerar os binários, podem executar testes de forma automática e descartar um build gerado se algum dos testes não passar, notificando os desenvolvedores nestes casos. Entre os serviços que provêm estas funcionalidades, pode-se citar o Microsoft Team Foundation Server, TeamCity, CruiseControl, dentre outros.

Apesar da existência deste recurso, ainda é comum que os desenvolvedores gerem os binários diretamente de sua máquina de desenvolvimento e publiquem em produção desta forma. Esta prática gera problemas como o software se comportar diferente quando publicado de máquinas diferentes, pois um desenvolvedor esqueceu de realizar o check-in de uma mudança que foi para produção ou o código só compila na máquina de fulano, dentre outras situações.

Neste ponto, é possível observar que houveram avanços desde quando o artigo foi escrito. Hoje se houve muito falar em “integração contínua” que tem relação com a preocupação por trás dessa pergunta (e mais ainda com a próxima), mas ainda não é algo presente em todas as empresas de tecnologia.

3 – Você realiza builds diários?

Ao se automatizar o processo de construção do software, torna-se possível práticas como builds diários. Esta prática determina que diariamente, em um horário fixo, seja feito um build a partir do código no sistema de controle de versão para validar os check-ins (commits) realizados entre o build anterior e o atual. Caso aconteça algum problema, os desenvolvedores devem trabalhar para corrigir o problema o mais rápido possível. Estes builds podem ocorrer durante a noite (os chamados nightly builds) ou como sugerido pelo artigo, durante o almoço. A sugestão deste horário é para que todos os desenvolvedores adquiram uma rotina de realizar o check-in das mudanças antes de irem almoçar e, ao voltar, possam tomar as ações pertinentes ao status do build: em caso de sucesso, obter a versão mais atualizada do código-fonte no servidor e continuar trabalhando; em caso de falha, o responsável por “quebrar” o build possa corrigir o problema enquanto os demais desenvolvedores continuem trabalhando com a versão pré-build, sem serem afetados.

Esta é uma prática interessante e ajuda a equipe de desenvolvimento a descobrir alguns dos bugs que foram gerados nas últimas 24 horas. Mas para alguns autores, não é suficiente para se ter integração contínua (Continuous Integration – CI). Segundo Martin Fowler, o maior propósito de se ter integração contínua é encontrar os bugs o mais cedo possível e com builds diários existirão problemas que não serão descobertos por um dia inteiro, o que torna a correção dos mesmos mais difícil (quanto mais tarde se descobre um bug, mais díficil e caro é corrigí-lo – mais a frente Joel fala sobre isso). O ideal segundo Fowler é que os builds ocorram sempre que um desenvolvedor realizar um check-in, condicionando o aceite deste ao sucesso do build. E por sucesso ele quer dizer que, além do build não “quebrar”, todos os testes automatizados devem ser executados com sucesso.

Times ágeis devem obrigatoriamente automatizar os builds e ter alguma forma de integração contínua. Hoje é uma prática bem difundida entre as equipes de desenvolvimento de software, mas não necessariamente adotada por todas.

4 – Você tem um banco de dados de bugs?

Ter uma base dos bugs da aplicação é essencial para se ter código de qualidade. Segundo o artigo, muitos desenvolvedores acham que conseguem guardar “de cabeça” os bugs existentes, mas isso é impossível a partir do momento que o número aumenta, o que torna necessário estes bugs estarem registrados em algum lugar. Ele sugere que seja utilizado algum software para bugtracking mas se existir alguma resistência em adotar esse tipo de software pela complexidade, basta ter uma tabela com informações básicas dos bugs, como passos para reprodução, comportamento esperado, comportamento atual, para quem está atribuído e seu status.

A utilização de soluções de bugtracking como Bugzilla , JIRA, TFS e Mantis são comuns hoje em dia e esta pode ser considerada uma prática bem difundida.

5 – Você corrige os bugs existentes antes de escrever um novo código?

Corrigir um bug assim que descoberto diminui o custo da correção, pelo fato do desenvolvedor ainda ter o código “fresco” na sua memória, o que torna a correção mais rápida. Os gerentes de projeto devem considerar em seus cronogramas o tempo para correção de bugs. Caso contrário, pode ocorrer o que ele chama de “método de infinitos defeitos”, onde os desenvolvedores se preocupam apenas em cumprir o cronograma de entregas em detrimento à  qualidade do código. Além disso, o cronograma de um software com poucos bugs é mais preciso do que um com vários bugs em aberto, pelo fato de ser difícil estimar o tempo de correção de determinadas falhas. Por estes motivos, o artigo sugere que os bugs existentes devem ser corrigidos antes de se escrever novas funcionalidades.

Técnicas ágeis como lean development, kanban e DoD (Definition of Done) adotadas hoje em dia por algumas equipes ajudam a resolver este problema. Um desenvolvedor só pode começar a trabalhar em uma nova tarefa se as anteriores estiverem prontas, e por prontas pode-se entender que esteja devidamente testada. Esta definição de pronto (DoD) é a garantia que o processo funcionará e que as entregas têm uma qualidade mínima.

6 – Você tem um cronograma atualizado?

Ter um cronograma atualizado é importante para o planejamento estratégico da empresa em relação ao produto em desenvolvimento. Desenvolvedores, segundo o artigo, tendem a dizer que estará pronto “quando estiver pronto” à equipe de negócios, o que não é aceitável devido às muitas decisões importantes que estão associadas ao cronograma do projeto.

O objetivo de um cronograma é tentar prever o que estará pronto até determinada data. Levando esta necessidade para o mundo ágil, esta informação pode ser obtida através do cruzamento do backlog e da velocidade do time. Portanto, é importante ter um backlog atualizado e devidamente priorizado, além do histórico do que foi feito nas últimas iterações para se calcular a velocidade do time e assim forma, ser possível estimar quais serão as entregas dos próximos sprints.