Boas práticas de programação: desenvolvendo códigos

     

       Recentemente tenho trabalhado no desenvolvimento de um sistema de automação para gerenciamento de produção. Conforme fui trabalhando dia após dia, vi o sistema crescendo. Percebi também que a complexidade do código cresceu junto e surgiu inicialmente a necessidade de criar padrões de organização, separar interfaces, scripts, tabelas, tags e outros por funcionalidade ou por tema, por exemplo separar os códigos de cadastros de produtos dos códigos de pedidos.
Em seguida, comecei a perceber que os códigos mais antigos eram bem diferentes dos códigos mais novos, percebi que conforme ganhava habilidade, escrevia códigos que eu classificava como melhores que os anteriores ou por serem mais legíveis ou por serem mais organizados ou ainda por dividir funções grandes em menores, meu chefe e meus colegas me tranquilizaram e disseram que isso é perfeitamente normal, que eles também percebem isso e refazem muitos códigos, ufa!
           Com isso, comecei a entender que um bom código pode facilitar muito na hora de revisar algo, perdia mais tempo procurando e entendendo os códigos mais antigos do que os mais novos. Então procurei por bibliografias a respeito deste tema e notei que muitos profissionais têm essa mesma visão.
             Segundo o livro “Código Limpo: Habilidades Práticas do Agile Software” do autor Robert C. Martin, códigos ruins geram atrasos consideráveis, muitos programadores passam por isso. Em um código ruim pelejamos para encontrar nosso caminho, esperando por alguma dica, alguma indicação do que está acontecendo, mas o código fica cada vez mais sem sentido. Conforme a confusão aumenta, a produtividade diminui. Contratar mais profissionais não resolve o problema pois as novas pessoas não conhecem as particularidades do sistema, não sabem a diferença entre uma mudança que altera o propósito do projeto e aquela que o atrapalha. Junto a isso, a pressão sobre toda a equipe para aumentar a produtividade, leva à criação de mais confusões que provavelmente levarão a produtividade mais próxima a zero.   
         No final, a equipe reclama para a gerência que não conseguem mais trabalhar neste código-fonte. Mesmo sem querer gastar recursos em um novo projeto, a gerência não pode negar que a produtividade está baixa e autoriza o grande replanejamento, pois parece mais simples começar do zero do que prosseguir com um código ruim. Segundo os profissionais que já passaram por uma situação semelhante a essa, perceberam que dedicar tempo para limpar o código não é apenas eficaz em termos de custo, mas uma questão de sobrevivência profissional.
        Junto a isso, temos o fato de que a grande maioria dos softwares nunca está completamente finalizado, sempre há a necessidade de novas atualizações e lançamento de novas funcionalidades, assim como eventuais modificações para a necessidade de uso de um novo cliente. Além disso, por um motivo ou outro, as modificações podem precisar ser realizadas por outro colaborador que não o desenvolvedor original.  Pensando dessa forma, caso o código não seja limpo e legível, a manutenção e o desenvolvimento se tornarão cada vez mais complicados.
         Surge então a pergunta: o que faz um código ser considerado limpo? Segundo Martin 2011, o código limpo é centralizado. Cada função, cada classe, cada módulo expõe uma única tarefa que nunca sofre interferência de outros detalhes ou fica rodeada por eles.  Segundo Grady Booch, autor do livro “Object Oriented Analysis and Design with Applications”, um “código limpo é simples e direto. Ele é tão bem legível quanto uma prosa bem escrita. Ele jamais torna confuso o objetivo do desenvolvedor, em vez disso, ele está repleto de abstrações claras e linhas de controle objetivas”.
     Já para Ron Jeffries, autor de “Extreme Programming Installed and Extreme Programming Adventures in C#”, um bom código é aquele que efetua todos os testes, que não apresenta duplicação de código, que expressa todas as ideias do projeto e minimiza o número de entidades, como as classes, funções, métodos e outras. Afirma ainda que de todas, presta maior atenção à duplicação, pois quando a mesma coisa é repetida várias vezes, é um sinal de que a ideia que temos na cabeça não está bem representada no código.
         Portanto, algumas dicas para criar códigos limpos e evitar que se chegue ao ponto de recomeçar um projeto por causa de um código mal escrito são:

Os nomes que você escolhe importam muito

                O nome de uma variável, função ou classe deve informar o porquê existe, o que faz e como é usado. Se um nome requer comentário, então ele não revela seu propósito. Não tenha medo de nomes grandes, pois um nome bem descritivo possibilita uma melhor compreensão posteriormente.

Outras dicas práticas são:

·         Classes e objetos devem ter nomes com substantivo(s), como “cliente” ou “conta”.
·         Métodos ou funções devem conter verbos, como “DeletarPagina” ou “Salvar”.
·         Selecione uma palavra por conceito pois é confuso ter “getName” e “recuperarNome” como métodos equivalentes de classes distintas.
·         Faça distinções significativas, não há como diferenciar “moneyAmount” de “money”, nem “customerInfo” de “customer” ou “accountData” de “account”. Utilize nomes que façam o leitor compreender as diferenças.
·         Evite informações erradas, não se refira a um grupo de contas como “accountList”, a menos que realmente seja uma “List”. A palavra “list” representa algo específico para programadores. Se o que armazena as contas não for uma “List” de verdade, poderá confundir outras pessoas.

Funções

                “As funções devem fazer uma coisa. Devem fazê-la bem. Devem fazer apenas ela.”

             Além de fazer uma única coisa, as funções devem ser pequenas e seguir a Regra Decrescente. Queremos poder ler o programa como se fosse uma série de parágrafos TO, cada um descrevendo o nível atual de abstração e fazendo referência aos parágrafos TO consecutivos.

             “Para incluir setups e teardowns, incluímos os setups, depois o conteúdo da página de teste e, então, adicionamos os teardowns.
                Para incluir setups, adicionamos o suíte setup, se este for uma coleção, incluímos o setups normal.
             Para incluir o suíte setup, buscamos na hierarquia acima a página ‘SuiteSetUp’ e adicionamos uma instrução de inclusão com o caminho àquela página. Para procurar na hierarquia acima...”

Comentários

                Comente o necessário e somente o necessário! Os códigos mudam e evoluem, movem-se de um lado para o outro, se bifurcam e se unem novamente. Porém infelizmente não acontece o mesmo com os comentários, que com o tempo, podem passar a ter um significado falso.
                Outra situação possível é que em códigos com muitos comentários, com o tempo, nossos olhos passam a ignorá-los. Sem falar que uma das motivações para escrever comentários é compensar por um código ruim. Então é melhor limpá-lo do que usar o tempo para escrever o comentário.
                A regra básica é, se for necessário escrever um comentário, nunca se esqueça de revisá-los para que não se tornem pistas falsas que atrapalham o leitor do código.

                Essas foram algumas dicas para melhorar os nossos códigos. Tenho consciência que mesmo conhecendo as dicas, aplica-las não é algo simples. Saber da importância de escrever um código limpo, não torna meus códigos automaticamente limpos, é uma prática que exige esforço constante e muita refatoração. Porém também sei que, sendo crítica em relação ao meu trabalho, a cada código escrito e reescrito estou mais próxima de um bom código! Espero que tenham gostado, se quiserem mais dicas, recomendo a leitura do livro. Ah, e como sempre, estou aberta a sugestões e críticas. Até a próxima.

Referências:


MARTIN, Robert C. et al. Código limpo: habilidades práticas do Agile software. Rio de Janeiro-RJ: Alta Books, 2011.

Comentários

Postagens mais visitadas deste blog

Como utilizar Tag Prefix WinCC Professional

TUTORIAL: Criando WinCC Tags a partir de documentos de texto utilizando script em Python

Utilizando interfaces, inversão de controle e injeção de dependências em programação - Um exemplo em C#