Boas práticas em Java e a sua importância
Boas Práticas vs Convenção
As boas práticas de desenvolvimento em Java, se referem a qualidade do código, com a intenção de deixá-lo mais otimizado, de mais fácil leitura e melhor organizado.
Já a convenção, significa literalmente um “acordo sobre determinada atividade, assunto, etc.”. Portanto, a convenção de determinada atividade no Java é um “acordo” da comunidade.
Certo, mas pra que isso serve afinal?
A finalidade dessa convenção é criar um “padrão” que faça com que organizemos o código da mesma forma aqui no Brasil ou em qualquer lugar do mundo.
Maus Hábitos de Iniciantes
No começo, todo mundo já teve dificuldade de entender o porquê da estrutura de um código ou de suas nomenclaturas.
Mas tenha em mente que existe um significado para tudo isso. Portanto, fazer diferente pode não ser “errado”, mas quebra o padrão utilizado pela comunidade.
O que também implica que por não ser errado, não é necessariamente correto. Ficou confuso? Relaxa! Vamos ver mais detalhes para entender melhor.
Existem inúmeras maneiras de organizar seu código. E nem sempre você fazer algo do seu jeito é errado.
Vou mostrar um exemplo a seguir:
public class Teste {
public static void main(String[] args) {
int somaDeDoisValores = 0;
somaDeDoisValores = 2 + 2;
int a=2+2;
}
}
Essas duas variáveis estão fazendo literalmente a mesma coisa.
Uma está de uma forma mais legível e a outra está de uma forma totalmente “comprimida”, mas as duas desempenham o mesmo papel. No entanto, suas organizações são completamente diferentes.
Ok, mas qual é o problema disso? De fato não há nenhum erro. Porém, as duas não estão seguindo boas práticas. Vou te explicar o por quê.
No primeiro exemplo, ela foi criada e iniciada antes de ser usada. Já no segundo exemplo, ela não tem uma convenção de nome adequado (detalhe: ela está totalmente “esmagada” sem espaços, e isso a torna um pouco menos legível. Isso deve ser considerado ao criar as variáveis).
Inicialização redundante
Mas e a inicialização redundante, o que é? É o ato você criar e iniciar as variáveis sem precisar delas.
No exemplo abaixo podemos perceber como isso funciona. Foram criadas três variáveis, e nenhuma delas é usada até a chamada do scanner. Isso, portanto, é uma má pratica que chamamos de inicialização redundante.
public class Teste {
public static void main(String[] args) {
String nome = "";
String sobrenome = "";
int idade=0;
Scanner scanner = new Scanner(System.in);
System.out.println("Digite seu nome: ");
nome = scanner.nextLine();
System.out.println("Digite seu sobrenome: ");
sobrenome = scanner.nextLine();
System.out.println("Digite sua idade: ");
idade = scanner.nextInt();
}
}
A maneira correta de se fazer as inicializações é criando a variável no mesmo momento que for utilizá-las.
Veja o exemplo a seguir:
public class Teste {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Digite seu nome: ");
String nome = scanner.nextLine();
System.out.println("Digite seu sobrenome: ");
String sobrenome = scanner.nextLine();
System.out.println("Digite sua idade: ");
int idade = scanner.nextInt();
}
}
Aqui, o código continua funcionando perfeitamente, se tornou menor, com uma leitura mais simples, mais organizado, e ainda está menos propenso a bugs.
Formatação do Código (Identação)
As IDE’s possuem uma formatação automática do código a qual chamamos de identação. Essa formatação por si só faz diversas coisas praticamente imperceptíveis.
Antes de abrir escopos com chaves “ { “ ela sempre deixa um espaço, por exemplo, ou quando há uma operação, ela também deixa espaços. Portanto, isso a=2+2;
se transformaria nisso a = 2 + 2;
por questões de organização e legibilidade.
São coisas tão simples que você pode se perguntar, mas isso faz diferença mesmo? E a resposta é: com toda certeza!
Como é uma convenção da comunidade deixar esses espaços e outros detalhes, quando alguém ler um código que não está seguindo todas essas “regras” essa diferença será notada.
Nesse caso, existem duas opções: a pessoa pode imaginar que o programador que fez isso não é tão experiente a ponto de ter o conhecimento, ou não se interessa por isso. E isso, pra quem está entrando na área, querendo entrar ou até mesmo tentando ser promovido, pode ser prejudicial.
Também há a questão de “lugares” onde há possibilidades de abrir escopos em lugares indevidos. Por convenção, sempre abrimos na mesma linha que a declaração de determinada funcionalidade como if/else e métodos, como no exemplo abaixo:
public class Teste {
public static void main(String[] args) {
if (true) {
System.out.println("Mandou bem com essa abertura de escopo!");
}
----------------------------------------------------------------------------------
if (true)
{
System.out.println("Mandou bem!");
}
----------------------------------------------------------------------------------
if (true)
{System.out.println("Mandou muito mal agora!");}
}
}
Portanto…
Nos três exemplos acima, todos vão funcionar normalmente.
Mas se você tem um costume com Java, os exemplos dois e três com certeza vão soar um pouco estranho pra você, porque geralmente usamos a opção número um. No entanto, apesar de não usarmos no dia a dia o exemplo dois, não se trata de uma má prática, e, finalmente no exemplo três é uma má prática e não é aconselhável usar.
Entretanto a boa noticia é que as IDE’s hoje em dia fazem isso pra você, basta usar o atalho e ela formata quase tudo, e, mesmo nos casos extremos em que a formatação não é inteira, a maior parte do código será formatada.
Caso você não saiba qual é o atalho utilizado para formatar sua IDE, faça uma pesquisa no Google. Com certeza em menos de 1 minuto você consegue achar o atalho.
Faça o teste de pesquisar pelo seguinte termo “atalho de formatação de código no eclipse”. A primeira resposta será a sua solução.
Se for em um ambiente diferente do “padrão” Windows, é só adicionar o seu sistema operacional, e com certeza será da mesma forma.
Nomes de Variáveis e Métodos
Existem muitas convenções de nomenclaturas. Mas como nesse artigo eu vou falar apenas de algumas, vou deixar o link aqui abaixo para as convenções de nomes da própria documentação da Oracle:
https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html
O primeiro tópico será o camelCase. Elas são palavras compostas sem espaços, como por exemplo: estouUsandoCamelCaseAgora.
Pode parecer estranho no primeiro contato, mas é assim que criamos nomes de variáveis, métodos e classes.
E lembre-se, quando formos nos referenciar a algo criado, devemos ter esse mesmo cuidado, porque Java é Case-sensitive. Isso significa que letras maiúscula e minúsculas são tratadas de formas diferentes, logo, uma variável com o nome de testeVariavel
não será reconhecida se tentar acessar por testevariavel
.
Mais um detalhe é que, variáveis e métodos devem conter suas iniciais minúsculas, e depois seguir o padrão camelCase. Diferente de Interfaces e Classes que devem ser criadas com seu nome iniciando com letra maiúscula.
Padrões de nomenclatura
Outro tópico extremamente importante e que muitas vezes é ignorado, são os significados dos nomes. Eles seriam nomes intuitivos, para que qualquer um que leia o nome da variável e método, consiga imaginar ou entender qual seu papel.
Isso pode até parecer muito simples e fácil, mas não é.
Então, sempre coloque nomes que mostrem o que aquilo significa ou faz. Não importa se ficar grande (obviamente, sem exagero) mas você pode, por exemplo, em um método que soma dois números, colocar o nome de somar()
. Não está errado, mas se você trabalhar com muitos métodos de cálculos, você pode ter somarDoisNumeros()
e somarTresNumeros()
e com isso se livrar daquelas variáveis e métodos com nomes de a
ou teste
. Quem nunca, né?
Outro ponto importante é aplicar uma padronização nos nomes dos métodos.
É aconselhável e de bom tom, usar os nomes no infinitivo e não no gerúndio na declaração de métodos, como por exemplo: pegarProdutos();, alterarProduto();, excluirProduto();
e não pegandoProduto();, alterandoProduto(); e excluindoProduto();
.
Ah, e muita atenção para não misturar criar um método excluindoProduto();
e outro alterarProduto();
nesse caso, ficará ainda mais desorganizado.
Não repita código
Existe um conceito extremamente importante na programação chamado DRY (Don’t repeat yourself ou “Não se repita”). Ele nada mais é do que, não repita código.
Pode não parecer, mas muitas pessoas desenvolvedoras não seguem esse conceito a risca, o que faz com que perguntemos: será que isso é realmente “fácil” de botar em prática?
Bem, não é tão simples assim, principalmente para estudantes. Em alguns momentos, não é tão “visível” a oportunidade de não repetir determinado código.
Mas como eu faço para não repetir código? É simples, principalmente por meio de métodos.
Também podemos reaproveitar códigos através da herança (com algumas limitações e consequências), e também pelo famoso CTRL + C
e CTRL + V
, que definitivamente é uma péssima escolha.
Então, o nosso herói pra reutilização de código são os métodos. Vamos ver alguns exemplos?
public class Teste {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Digite a primeira nota do aluno: ");
Double nota1 = scanner.nextDouble();
if (nota1 < 0) {
throw new Exception("O número não pode ser negativo.");
} else if (nota1 > 10) {
throw new Exception("O número não pode ser maior que 10");
}
System.out.println("Digite a segunda nota do aluno: ");
Double nota2 = scanner.nextDouble();
if (nota2 < 0) {
throw new Exception("O número não pode ser negativo.");
} else if (nota2 > 10) {
throw new Exception("O número não pode ser maior que 10");
}
System.out.println("Digite a terceira nota do aluno: ");
Double nota3 = scanner.nextDouble();
if (nota3 < 0) {
throw new Exception("O número não pode ser negativo.");
} else if (nota3 > 10) {
throw new Exception("O número não pode ser maior que 10");
}
Double media = (nota1 + nota2 + nota3) / 3;
System.out.println(media);
}
}
Note a quantidade de vezes que repetimos o if/else, que estão aí apenas para fazer uma validação simples, mas tornam o código bem grande por algo tão fácil e simples de resolver. O if/else verifica apenas se um número está entre 0 e 10 e lança exceção caso não esteja.
Agora vamos dar uma melhorada nesse código:
public class Teste {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Digite a primeira nota do aluno: ");
Double nota1 = scanner.nextDouble();
verificarNumeroValido(nota1);
System.out.println("Digite a segunda nota do aluno: ");
Double nota2 = scanner.nextDouble();
verificarNumeroValido(nota2);
System.out.println("Digite a terceira nota do aluno: ");
Double nota3 = scanner.nextDouble();
verificarNumeroValido(nota3);
Double media = (nota1 + nota2 + nota3) / 3;
System.out.println(media);
}
static void verificarNumeroValido(Double num) throws Exception {
if (num < 0) {
throw new Exception("O número não pode ser negativo.");
} else if (num > 10) {
throw new Exception("O número não pode ser maior que 10");
}
}
}
Note que agora eu fiz um método para executar essa verificação, e no momento em que for necessário fazer a verificação eu chamarei esse método passando o número que eu quero que ele verifique.
Nós fizemos uma refatoração e ficou melhor, certo? Mas dá pra melhorar ainda mais! Vamos lá:
public class Teste {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Digite quantas notas irá cadastrar: ");
int qtdNotas = scanner.nextInt();
ArrayList<Double> notas = new ArrayList();
for (int i = 0; i < qtdNotas; i++) {
System.out.println("Digite a " + (i + 1) + "° nota: ");
notas.add(scanner.nextDouble());
verificarNumeroValido(notas.get(i));
}
double soma = 0;
for (int i = 0; i < notas.size(); i++) {
soma += notas.get(i);
}
Double media = soma / qtdNotas;
System.out.println(media);
}
static void verificarNumeroValido(Double num) throws Exception {
if (num < 0) {
throw new Exception("O número não pode ser negativo.");
} else if (num > 10) {
throw new Exception("O número não pode ser maior que 10");
}
}
}
Perceba que agora nós temos mais recursos à nossa disposição como controle da quantidade de alunos, sem ter que ficar repetindo linhas para solicitar mais uma nota. Isso tudo é feito a partir de laços e métodos. Achou interessante?
Bônus Importante!
Não tenha medo de pesquisar, isso é extremamente importante! Não consegue fazer algo, não consegue corrigir algo? Pesquise!
Na programação, muita coisa que se faz é sabendo pesquisar! Isso acontece em todas as linguagens, é algo que se torna hábito depois de um tempo, e você nem vai perceber.
Não conseguiu baixar algo ou configurar algo? Pesquise.
A comunidade de programadores é muita ativa e com certeza alguém já passou pelo que você está passando, então, você vai ter alguma solução ou no mínimo, alguma coisa semelhante que você vai poder se basear nisso.
E caso não ache, pesquise em inglês. Suas chances aumentam drasticamente.
Ah, e não precisa saber inglês. Use o Google tradutor para fazer a pergunta, e depois traduza as respostas que encontrar. Assim você aprende muita coisa!
Então, eu sugiro fortemente que, antes de você procurar a ajuda de alguém, tente você mesmo! Portanto, leia e releia perguntas e respostas que já resolveram seu problema, pegue a mensagem de seu bug e bote no Google, leia artigos e veja vídeos.
Fonte: Cod3r