Na busca de qualidade ao desenvolver um aplicativo, é imprescindível a adoção de boas práticas. Pensando nisso, destacamos algumas delas que ajudam a manter o código mais legível, fácil de compreender e de manter. Lembre-se, para alcançarmos um bom código, não basta apenas que ele funcione.
Guia do artigo:
- Endentação
- Comentários e Documentação
- Pacote (Package)
- Convenções
- Tratamento de erros
- Padrões de Projetos
- Deprecation
- Testar e Depurar
- Backup/Restore
- Tamanho
O maior desafio das empresas de desenvolvimento de software é criar sistemas robustos, no menor tempo possível e com baixo custo. Para que isso aconteça, é imprescindível a adoção de boas práticas durante a programação, o que é apresentado neste artigo.
Essa é a primeira parte de uma série de artigos que irá tratar de boas práticas de programação. Para começar, pense em um pomar de qualquer tipo de fruta; se ele for plantado dentro de normas específicas como espaçamento entre as árvores, adubação, podado de forma correta e no tempo certo, irá gerar mais, melhores e maiores frutos. Essa técnica é passada de geração para geração, desta forma, qualquer pessoa saberá como proceder na manutenção do pomar e o resultado deverá ser sempre o mesmo. Podemos estender esse pensamento para o desenvolvimento de software, em que o uso de regras e boas práticas geram melhor legibilidade do código, contribuindo significativamente para que o ciclo de desenvolvimento de sistemas ocorra de maneira mais ágil, prática e de fácil manutenção.
Programadores mais experientes costumam dizer que “a pior coisa que existe é dar continuidade a um software desenvolvido por terceiros”. Provavelmente vocês já devem ter escutado um ditado que diz: “cada cabeça é uma sentença”, o que significa dizer que para resolver um mesmo problema, desenvolvedores podem usar caminhos completamente diferentes. Apesar disso, se na criação do código o programador seguir regras básicas usando as boas práticas de programação que serão mostradas nesse artigo, essa continuidade e manutenção no desenvolvimento de sistemas será facilitado e menos árduo.
A própria Oracle informa que 80% do custo de vida útil de um software são com os custos de manutenção do mesmo. Isso destaca que é preciso ter um olhar atento para que esse valor possa ser reduzido, e assim ser investido em outro setor. Criar um software é quase como criar um filho. Se o educar bem, provavelmente não terá decepção no futuro, do contrário, você terá longas dores de cabeça. Com software podemos analisar da mesma forma; se usar as boas práticas, não deverá sofrer lá na frente, do contrário, será um problema para o resto da vida.
Primeira boa prática: Endentação – Organizando o código
Todo programador inicia sua trajetória com Algoritmos e Lógica de Programação, e é aqui que ele deve ser orientado sobre as melhores práticas que deverão acompanhá-lo para o resto da sua vida. O primeiro ensinamento a ser passado é também o mais simples de todos, mas que se não for usado de forma adequada, dificultará muito o aprendizado e a leitura do código, é a endentação.
É muito comum vermos iniciantes em programação criando seus algoritmos de forma desorganizada e desalinhada. Chamamos isso de código não endentado, como mostra a Listagem 1. É visível a dificuldade do entendimento do mesmo, comprometendo inclusive o processo de aprendizado. Até um profissional precisa analisar com calma e muita paciência para entender o algoritmo, mesmo que ele tenha poucas linhas. Agora imagine um sistema com centenas delas. Fica praticamente impossível o desenvolvimento dessa maneira.
package br.com.javamagazine;
class Vendas implements InterfaceVendas{
public String nomeCliente;
protected String descProduto;
private double valor=50;
public double altera_valor(double valor){
this.valor = valor;
return valor;
}
public void imprime(double valor){
if (valor>100)
JOptionPane.showMessageDialog(null,"Valor acima do permitido");
else JOptionPane.showMessageDialog(null,"Valor="+valor);
}
}
Já na Listagem 2, vemos que o mesmo código, agora endentado, fica muito mais legível, limpo e esteticamente mais bonito. Mesmo que você programe sozinho, deve adotar esta boa prática, e se compartilhar o fonte com outras pessoas, é obrigatório para que o projeto não empaque nesse pequeno grande detalhe.
package br.com.javamagazine;
import javax.swing.JOptionPane;
class Vendas implements InterfaceVendas {
public String nomeCliente;
protected String descProduto;
private double valor = 50;
public double alteraValor(double valor){
this.valor = valor;
return valor;
}
public void imprimeValor(double valor){
if (valor > 100)
JOptionPane.showMessageDialog(null,"Valor acima do permitido");
else
JOptionPane.showMessageDialog(null,"Valor="+valor);
}
}
Em algumas linguagens de programação, endentar é tão importante que faz parte de seu desenvolvimento. Isso quer dizer que para iniciar e fechar blocos de códigos, não precisa digitar identificadores como { e }, basta endentar que o compilador da linguagem consegue interpretar como sendo o início e o fim do bloco.
Segunda boa prática: Comentários e Documentação
Atire a primeira pedra quem nunca deixou de comentar um código e depois não se lembrava mais da funcionalidade do algoritmo que você mesmo escreveu. No momento em que se está programando, para você e para Deus fica muito clara a finalidade daquela classe, do método ou da variável, porém, passado algum tempo, somente Deus saberá a lógica daquele código, e você poderá não fazer a mínima ideia. Muitos programadores ignoram a importância dos comentários no seu arquivo fonte, geralmente por falta de conscientização dessa boa prática para que o mesmo não gere dor de cabeça no futuro. Você pode usar comentários com duas finalidades:
- Explicar o algoritmo ou a lógica usada, mostrando o objetivo de uma variável, método, classe...;
- Documentar o projeto, descrevendo a especificação do código. Desta maneira, qualquer pessoa poderá analisar um arquivo de documentação, mesmo que este não apresente o código fonte. Através de uma ferramenta chamada javadoc é possível gerar documentação baseada em tags específicas que você coloca no seu código fonte.
O primeiro comentário deve ser colocado no início do arquivo indicando o objetivo do mesmo através de um pequeno resumo. Ao criar um método, procure sempre informar qual é a finalidade do mesmo e se ele irá retornar ou não alguma informação. Em muitas variáveis criadas, somente através de seu nome nem sempre é possível saber que informação ela irá armazenar ou para que ela servirá, por isso, não deixe de comentá-la nesses casos.
Cansamos de ouvir “tudo o que é demais pode ser ruim”. Essa premissa vale para comentários, que pode deixar o código poluído, difícil de ler e atualizar. Por isso, tenha bom senso quando comentar as linhas do sistema, colocando textos curtos e somente aqueles que você achar relevante para a leitura e principalmente para a compreensão do código. E quando achar necessário colocar um comentário para que outras pessoas consigam entender o algoritmo, procure rever o seu código. Talvez melhorando ele, nem seja necessário colocar essas informações adicionais.
Na Listagem 3 vemos um código com comentários. Observe que logo no começo do arquivo foi colocado um bloco de comentários usando os delimitadores /*..*/. Depois do import, foi inserido /**..*/. Esse delimitador indica que o comentário presente dentro ele será usado pelo javadoc para gerar documentação no formato HTML. Também é possível colocar um comentário de linha utilizando //, como mostrado para explicar a variável media.
/*
* Procure sempre comentar no início do arquivo fonte colocando informações como
* Nome da Classe, Data da Criação
* Todos os direitos reservados para Nome da Empresa e o endereço desta completo
* Outras informações que achar necessário.
* Se você não for gerar documentação ou se um comentário não é adequado para isso,
* também pode colocá-lo aqui
*/
package br.com.devmedia;
import javax.swing.JOptionPane;
/**
* A informação que você colocar aqui irá para a documentação gerada através do javadoc.
* @version 1.0
* @author Neri Aldoir Neitzke – Universidade Ulbra
*/
public class CalcMedia {
public static void main(String args[]){
float nota1, nota2, media;
nota1 = 5;
nota2 = 7;
media = (nota1 + nota2) / 2; //calcula a media do aluno
if (media >= 6)
JOptionPane.showMessageDialog(null,"Aprovado com média " + media);
else
JOptionPane.showMessageDialog(null,"Reprovado com média " + media);
}
}
Não é objetivo do artigo ensinar a gerar documentação e nem as tags usadas. Queremos apenas conscientizar de sua importância e lembrar que as pessoas tendem a evitar a leitura de comentários muito extensos. Deste modo, coloque somente o que importa e em poucas linhas.
Terceira boa prática: pacote (package)
Pare e pense: você é uma pessoa organizada? Ou é daqueles que chega em casa e joga os sapatos para um lado, a camisa para outro, e quando vai sair não consegue achar aquele par de meias preferido? Normalmente a mesma organização da vida pessoal é levada para a profissional, sendo assim, seu computador e seu estilo de armazenar os arquivos e pacotes terão o mesmo reflexo.
Em desenvolvimento de software, a organização dos arquivos é imprescindível. Neste ponto entra nossa terceira boa prática, que é o uso de pacotes (package) para que possamos separar os códigos em categorias, contribuindo para um projeto elegante e ordenado. Imagine um pequeno sistema com apenas cinco classes. Nesse caso você poderia deixar tudo em uma única pasta; mas e se este projeto aumentar? Ter um acúmulo de classes em um único diretório poderá dificultar a compreensão sobre as mesmas, o que reduz a produtividade durante o desenvolvimento. Deste modo, procure separá-las por categorias, funcionalidades ou pela relação que existe entre elas. A Figura 1 exemplifica o uso de pacotes (ex: br.com.ulbra.cadastro).
Quarta boa prática: Convenções de nomes para classes, métodos, variáveis...
Usando as boas práticas já citadas e acrescentando a isso convenções de nomes, você irá tornar a leitura do programa muito mais fácil.Colocando nomes adequados e padronizados, você passará informações que ajudarão na compreensão do código, indicando, por exemplo, o que uma variável irá armazenar ou o que um determinado método irá fazer. Se você agregar a isso uma boa convenção de nomes, o ajudará muito no ciclo de desenvolvimento do sistema, como podemos ver abaixo:
- Pacotes: a primeira convenção de nomes que será mostrada é para pacotes. Imagine que você irá desenvolver um sistema para uma instituição de ensino, por exemplo a Universidade Ulbra. Durante o desenvolvimento, devemos agrupar as classes de acordo com seus objetivos. Por exemplo, para classes responsáveis pela interface com o usuário, podemos definir o pacote br.com.ulbra.view. Observando-o, facilmente identificamos que ele deve ser escrito de forma semelhante a um endereço web, só que de trás para frente. E ao final, indicamos um nome (ou um conjunto de nomes, preferencialmente separados por “.”), que classifica as classes agrupadas;
- Classes e Interfaces: ainda analisando a Figura 1, observe a classe chamada Conexao e perceba que os nomes das classes iniciam com uma letra maiúscula, sendo simples e descritivo. Quando a classe possuir um nome composto, como MenuPrincipal, o primeiro caractere de cada palavra deve ser sempre maiúsculo. Essas regras também são aplicadas para Interfaces;
- Métodos: o que difere a convenção de nomes de classes para nomes de métodos é que para os métodos a primeira letra deve estar em minúsculo. Como os métodos são criados para executar algum procedimento, procure usar verbos para seus nomes, por exemplo: imprimeValor();
- Variáveis: use a mesma convenção adotada para Métodos, criando sempre nomes curtos (nota, primeiroNome, mediaAluno) e significativos, em que ao bater o olho no nome, o programador já saiba que informação a variável vai armazenar.Evite nomes de variáveis de apenas um caractere (i, j, x, y), a não ser para aquelas usadas para índices em laços de repetição onde o algoritmo percorre vetores. Em variáveis finais (constantes), isto é, que possuem um valor fixo, todas as letras devem estar em maiúsculo e com as palavras separadas por sublinhado (“_”), por exemplo: TAXA_IMPOSTO;
Quinta boa prática: Tratamento de erros (try/catch)
O fantástico do ser humano é o fato de que quando achamos que todas as possibilidades já se esgotaram, vem um camarada e descobre algo novo, ou um problema novo. Nunca podemos desenvolver um sistema pensando que os usuários serão bons programadores ou feras em informática. Durante o desenvolvimento, temos que pensar nos usuários que podem inserir dados de forma incorreta, fazer coisas inimagináveis e que por isso seu código pode apresentar erros.
A realidade do dia a dia nas empresas pode mostrar a você um mundo novo, em que um usuário, em vez de seguir um manual ou suas orientações, pode querer usar o sistema à sua própria maneira, e se o sistema não previr todas essas possibilidades, se prepare para uma grande dor de cabeça. Além destes, existem erros externos que podem ocorrer, como uma impressora desligada, queda de conexão com a internet, um disco encher ou o computador ficar sem memória. Independente do problema ocorrido, seu sistema deve (pelo menos) avisar o usuário o que aconteceu, evitar automaticamente a perda de dados (salvar) e permitir, de forma elegante, que ele possa continuar sendo usado sem maiores traumas.
Todas as linguagens de programação têm suporte ao tratamento de erros, mas nem sempre seu uso é obrigatório; não se iluda por isso, é aí que mora o perigo. Java é considerado uma linguagem robusta, e um dos motivos é o fato dela exigir que você use o try..catch em determinadas situações, como no acesso ao banco de dados ou para a seleção de um arquivo externo qualquer. Isso já garante a você (mesmo não sabendo) o uso de uma boa prática. Para outros casos, é altamente recomendável o tratamento de erros, oferecendo assim maior segurança e confiabilidade ao sistema. O básico do tratamento de erros é o sistema mostrar uma mensagem quando uma exceção ocorrer, o que deve ser feito tanto na fase de desenvolvimento, para o programador, quanto para o usuário final, quando o sistema estiver em produção (isto é, sendo utilizado).
Ao acontecer algum imprevisto, procure fazer com que o sistema comunique o usuário do problema ocorrido e permita que a operação aconteça novamente. O Java permite tratar os principais erros com bibliotecas específicas, por isso evite usar apenas a classe Exception, pois ela é muito genérica e dificultará a localização do erro real. Além disso, procure não usar tratamento de erros em blocos muito grandes, pois dificulta a localização do problema – a não ser que seja extremamente necessário. Quando isso acontecer, tente melhorar o código para que ele não fique tão longo. Uma dica para isso pode ser a implementação de novos métodos. A Listagem 4 mostra um exemplo do uso de try..catch.
public boolean conecta(){
boolean result = true;
try { //tenta conectar
Class.forName(driver); //carrega o driver do banco
conexao = DriverManager.getConnection(url, usuario,senha);
JOptionPane.showMessageDialog(null, "Conexao com sucesso");
}
catch(ClassNotFoundException erroClass) {
JOptionPane.showMessageDialog(null, "Driver não Localizado: "+erroClass);
result = false;
}
catch(SQLException erroBanco){
JOptionPane.showMessageDialog(null, "Problemas na comunicação com o banco: "+erroBanco);
result = false;
}
return result;
}
Quem já passou pela experiência de usar um software que não funcionava sabe o quanto isso é desagradável. Um sistema que envolva cálculos matemáticos deve prever que o usuário digite somente números, evitando que ocorram erros. Mesmo assim, você pode usar NumberFormatException para tentar converter a String para um formato numérico. Da mesma forma, em um cadastro de clientes, faça com que seu software não permita a inserção de números onde é exigido somente texto, como no campo nome, por exemplo.
Aqui, falamos sobre a possibilidade de erros externos ou humanos, mas também podem acontecer erros de lógica. Deste modo, os localize para que não aconteçam depois da fase de desenvolvimento. Entretanto, não é possível garantir que todas as funcionalidades de um software funcionem corretamente, sem erros, principalmente em grandes projetos, em que muitas pessoas estão envolvidas. Para auxiliar esta questão, podemos utilizar refatoração, integração contínua, testes, entre outros mecanismos, mas isto fica para artigos futuros.
Sexta boa prática: Padrões de Projetos (Design Patterns)
No inicio dos anos 90, em que as linguagens como Clipper e Cobol eram muito utilizadas, “padrões de projeto” eram palavras que praticamente não existiam no vocabulário dos desenvolvedores. Outra característica marcante da época é que a programação era completamente estruturada, gerando assim milhares de linhas a mais do que é feito hoje, e tudo isso sem um padrão específico. No entanto, essa metodologia de desenvolvimento deixou de ser viável devido ao aumento da complexidade das aplicações. Deste então, viabilizados pela Programação Orientada a Objetos, os programadores começaram a separar os códigos do programa, dividindo-os em camadas. É aqui que entra o padrão MVC (Model-View-Controller), mostrado na Figura 2 e explicado abaixo:
- Model:é a camada principal. Model (ou Modelo) será responsável pela manipulação dos dados e pelas operações que o sistema irá executar, ou seja, tudo o que o software vai fazer passa por ele;
- View: é a camada de apresentação, ou seja, o que o usuário final irá visualizar. Por ser uma camada independente, a pessoa (ou equipe) responsável por trabalhar nela poderá se dedicar integralmente no seu layout, deixando-o rico em design para conquistar o cliente, e sem a necessidade de conhecer os detalhes de programação das demais camadas;
- Controller: também conhecido como Controlador, é responsável por gerenciar todas as informações no sistema, definindo o comportamento do programa. Como exemplo, pense em uma página de login; o Controller poderia verificar (através da camada Model) se o nome e a senha do usuário estão corretos, e retornar essa informação para a camada View, atuando diretamente entre os dois.
Com o uso da programação em camadas, será mais fácil e produtivo ter várias pessoas em um mesmo projeto de software, permitindo dividir melhor as funcionalidades da aplicação. Dessa forma, enquanto algumas pessoas trabalham na camada de visão, outras poderão manipular o código relacionado às regras de negócio ou que controlam o fluxo das informações.
Outras boas práticas
Muitas empresas de desenvolvimento estão adotando o uso de boas práticas para melhorar a qualidade de seus códigos e reduzir custos (principalmente no que diz respeito à manutenção). Mas essa busca é contínua, e com a evolução das linguagens, o que hoje é uma boa prática, amanhã pode não ser mais. Por isso, é preciso estar sempre atento às mudanças.
Abaixo listamos alguns exemplos que podem ser usados para melhorar esse processo:
- Deprecation: na medida em que as linguagens vão evoluindo, uma classe, método ou interface que você usou algum tempo atrás pode estar desatualizado, obsoleto ou até mesmo inativo. Um exemplo disso é o método show(), empregado em aplicações desktop para carregar um formulário. Atualmente, para esta mesma funcionalidade, devemos utilizar setVisible(). Por isso, ao dar manutenção em um código e/ou migrá-lo para uma nova versão do Java, procure analisá-lo e fazer as mudanças necessárias. Para facilitar esta tarefa, as IDEs modernas, como NetBeans e Eclipse, facilitam o nosso trabalho destacando estes elementos no código;
- Testar e Depurar: não muito tempo atrás, praticamente não existia testes de software, a não ser o que o próprio programador fazia durante o desenvolvimento do sistema, ou seja, validação dos dados e testes com alguns registros – o que sempre foi muito pouco. No entanto, devido ao surgimento de novas tecnologias, o aumento da complexidade dos programas e a busca por qualidade, os testes de software ganharam um espaço muito importante dentro do ciclo de desenvolvimento de sistemas. Assim, procure executar muitos testes no seu sistema e também aprenda a usar um depurador para analisar o código em tempo de execução. Desta forma, será facilitada a localização de defeitos que muitas vezes não aparecem na compilação por serem erros de lógica. Muitos programadores desconhecem a depuração fornecida pelas evoluídas IDEs, que oferecem a possibilidade da execução passo a passo de um programa, mas usam a famosa impressão (System.out.println()) para depurar sua classe. No entanto, essa não é uma forma prática e elegante de depurar erros;
- Backup/Restore: essa dica é tão antiga quanto importante, mas que muitos só percebem sua relevância quando perdem códigos e têm que refazê-los. Portanto, não deixe de fazer backups com determinada frequência (ao final do dia ou semanalmente, por exemplo);
- Tamanho: evite classes muito longas; com mais de 1000 linhas já fica muito complicado sua leitura e depuração, por isso devem ser evitadas. Se o código estiver muito grande, é possível que seu algoritmo precise ser revisado, pois pode estar fazendo mais do que necessita.
Conclusões
Criar softwares não é uma arte em que cada um pode fazer à sua maneira. Existem convenções e padrões para deixar o código mais legível, facilitando a vida da equipe de desenvolvimento, oferecendo maior qualidade e reduzindo custos.
Você terá muita dificuldade para localizar erros ou dar manutenção se não codificar de maneira simples, clara, organizada e tendo o cuidado de adicionar comentários. Programar bem e programar mal dão o mesmo trabalho na escrita, mas na alteração, quem não seguir as regras básicas, terá muito mais trabalho, então, a escolha é sua!