Executando verificação de segurança...
1

Ajuda: Como criar bons "if"s?

Já ouvi falarem que o bom é evitar muitos if else, else if, e tentar lidar primeiro com a entrada considerada "errada" ou um erro, para depois lidar com a entrada que você realmente "quer" para dar continuidade no código, então queria ver a opinião de vocês sobre como criar bons "if"s?

Carregando publicação patrocinada...
3

tentar lidar primeiro com a entrada considerada "errada" ou um erro, para depois lidar com a entrada que você realmente "quer" para dar continuidade no código

Isso é conhecido como early return, a ideia é que vc teste os casos inválidos primeiro, e já retorne o respectivo erro. E só depois que já tem certeza que não há erros, aí vc vai pro trabalho propriamente dito. Ex:

function fazAlgo(nome, idade) {
    if (nome === null || nome === '') {
        return NOME_INVALIDO; // retorna algum código de erro específico
    }
    if (idade < 18) {
        return SOMENTE_MAIORES_DE_18; // retorna outro código de erro específico
    }

    // aqui eu já sei que o nome e idade são válidos, e posso continuar
    // ... código que faz algo com o nome e idade
}

Quanto a "evitar muitos if/else", depende. Quanto é "muitos"? Se vc tem vários casos diferentes pra testar, e precisa verificar um a um, pode ser que não tenha outro jeito a não ser fazer um if pra cada. Cada caso é um caso.

O que eu vejo de exemplos ruins é o fato de muitos não entenderem que, uma vez que o código não entra em um if, vc não precisa testar de novo a mesma condição nos demais if's. Um exemplo clássico é:

// redundante, os mesmos valores aparecem mais de uma vez
function verificaIdade(idade) {
    if (idade < 0) {
        console.log('idade inválida');
    } else if (idade >= 0 && idade < 18) {
        console.log('menor de idade');
    } else if (idade >= 18 && idade < 60) {
        console.log('adulto');
    } else if (idade >= 60) {
        console.log('idoso');
    }
}

Repare que os valores 0, 18 e 60 são usados duas vezes cada. Mas na verdade não precisa disso, pois o código pode ser apenas:

// sem redundância
function verificaIdade(idade) {
    if (idade < 0) {
        console.log('idade inválida');
    } else if (idade < 18) {
        console.log('menor de idade');
    } else if (idade < 60) {
        console.log('adulto');
    } else {
        console.log('idoso');
    }
}

Pois se a idade não for menor que zero, ela não entra no primeiro if. Ou seja, se chegou no primeiro else é porque com certeza é maior ou igual a zero, então não preciso testar isso de novo (se não fosse maior ou igual a zero, teria entrado no primeiro if). Eu só preciso testar a nova condição, que é se a idade é menor que 18.

Da mesma forma, se não entrou no segundo if, é porque não é menor que 18, então se chegou no segundo else é porque com certeza é maior ou igual a 18, e não precisa testar isso de novo.

Por fim, se não entrar em nenhum if, é porque com certeza é maior ou igual a 60, então no último else não preciso de um if.

Assim fica não só mais claro e sucinto, como também facilita na hora de mudar as faixas de valores. Por exemplo, se quiser incluir uma faixa entre 18 e 21 e outra entre 22 e 60, a alteração fica mais simples no segundo código.

Isso vale como regra geral: se algo já foi testado antes, não precisa repetir novamente. Um bom conhecimento de álgebra booleana ajuda bastante nesse sentido.


Aproveitando, acabei de ver em outro site um exemplo de if ruim (em PHP):

$dias = array("Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado");
$falta = "Quinta-feira";

if ($falta == "Segunda-feira") {
    echo "$dias[1] $dias[2] $dias[3] $dias[4] $dias[5]";
} elseif ($falta == "Terça-feira") {
    echo "$dias[0] $dias[2] $dias[3] $dias[4] $dias[5]";
} elseif ($falta == "Quarta-feira") {
    echo "$dias[0] $dias[1] $dias[3] $dias[4] $dias[5]";
} elseif ($falta == "Quinta-feira") {
    echo "$dias[0] $dias[1] $dias[2] $dias[4] $dias[5]";
} elseif ($falta == "Sexta-feira") {
    echo "$dias[0] $dias[1] $dias[2] $dias[3] $dias[5]";
} elseif ($falta == "Sábado") {
    echo "$dias[0] $dias[1] $dias[2] $dias[3] $dias[4]";
}

A ideia é imprimir todos os dias, exceto o que estiver setado em $falta. Este é um caso que até "funciona", mas o if/else não é o mais adequado. O mais simples é fazer um loop pelo array, e só imprimir os dias que são diferentes de $falta:

foreach ($dias as $dia) {
    if ($dia != $falta) {
        echo "$dia ";
    }
}

Ainda tem um if, mas agora é um só. E ao contrário do outro código, funciona para arrays de qualquer tamanho. Além de, é claro, ser mais simples, sucinto, fácil de entender e manter.

Mas isso não quer dizer que uma sequência de if/else sempre é ruim. Cada caso é um caso.

1

Cara o @filipedeschamps fez um If' delicinha no canal dele, usando javascript, acredito que funciona com PHP também. consiste em ter um array e o $falta seria chave do array.
https://www.youtube.com/watch?v=Lf3ZV0UsnEo

sobre o quanto é muito If's realmente é um grande DEPENDE.
Mas tem uma trilha do alberto sobre complexidade cognitiva que gosto bastante.
https://www.youtube.com/watch?v=rqw_Jnv6ZX4
ele tem bastante conteudo sobre isso, e inclusive tem um plugin pro VSCode que faz a analise estatica no código de acordo com suas preferencias.

1

Nesse caso específico, não vejo vantagem em deixar a $falta como chave. Porque no exemplo que coloquei, ela indica o valor que não é pra imprimir, então o for me parece mais simples.

Mas claro que cada caso é um caso. Tem vezes que compensa ter uma estrutura diferente, e as soluções variam conforme o problema. Tudo depende.

2

Quem disse?

Isso ajuda a ilustrar o que eu sempre falo sobre boas práticas, inclusive em minha palestra "A péssima prática de seguir boas práticas".

Nem sempre quem fala sobre a tal boa prática é uma autoridade no assunto. Pode até ser uma pessoa famosa, mas não quer dizer que seja autoridade. Mesmo que seja, ela pode errar naquele ponto.

Mas o pior é que as pessoas passam repetir aquilo, muitas vezes perdendo a essência do que ela diz. E aí vem o que é o problema da boa prática.

Sem explicação do motivo dela ser assim, ela é ruim. Sem considerar o contexto que vai usar, ela é ruim. Se você sabe a motivação de usar ela não é mais uma boa prática e sim uma técnica com justificativa. É um conhecimento adquirido para aplicar conforme o contexto.

Então antes de saber como fazer isso, deveria saber porque deveria. Se ninguém explicou, ignore, é "cagação de regra". Com a explicação muda tudo, mesmo que seja o mesmo resultado. E isso deve valer para qualquer coisa na vida. Questione tudo o que te empurram. Ainda mais em programação. Sua função profissional é questionar.

Tem casos que:

  • deve sim evitar um if, e usar uma sobrecarga, ou polimorfismo
  • deve suprimir um if ou um else que claramente é desnecessário por causa da lógica aplicada ali
  • pode ser melhor usar um switch ou um pattern matching
  • deve compor a condição para resolver em apenas um if que executa a mesma coisa.
  • pode ser que seja melhor usar um operador condicional (que as pessoas chamam equivocadamente de ternário).
  • deve mudar a ordem de execução para evitar o if (early return ou faz entrar em um primeiro, não precisa mais verificar os outros)
  • um try-catch pode ser melhor, ainda que costuma acontecer mais o contrário e o usam onde deveria ter um if
  • um monte de if pode virar um só dentro de um laço
  • precisa da condição mas não do if.

Por exemplo:

if (x ==1) return true;
else return false;

   
pode ser escrito como:

return x == 1;

   
Esse é um exemplo. Em cada caso pode ter situação que merece reduzir. De forma geral fica complicado dizer. Não pegue uma solução e fique procurando um problema para aplicá-la, quando tem um problema, procure pela solução.

Não dá para reduzir um if absolutamente necessário.

Dá para seguir outras regras, que não são o if em si, como por exemplo, em vez de fazer uma condição, chamar uma função ou variável com um nome significativo para pegar o resultado no if. Isso evita comentários. Mas tem casos que não precisa de nada disso. Tem caso que o comentário é melhor.

aceito = x == 1;
if (aceito) return Status.Aceito;

Precisa aprender álgebra booleana para reduzir ou compor as expressões lógicas. Não é o if mas é como usá-lo melhor. Expressão lógica é uma coisa, if (comando de seleção e desvio) é outra bem diferente, e precisa entender isso.

E estude toda a computação, para ter subsídios, ferramentais na sua mente que permitam você tomar a melhor decisão.

Procure dar exemplos para saber como reduzir cada um deles. Pode ser que a questão nem seja do if em si, pode ser a expressão lógica, ou a organização do código em torno dele.

Eu e outras pessoas já respondemos bastante sobre isso, nem vou pesquisar tudo, só alguns exemplos:

Não tem atalhos para aprender programação. Até tem, mas eles não te levam pro mesmo caminho.

Faz sentido para você?

Espero ter ajudado.

Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente. Para saber quando, me segue nas suas plataformas preferidas. Quase não as uso, não terá infindas notificações (links aqui).

1

E aí! Tudo bem? Sobre diminuir a quantidade de "if's" e "else's" no código, recomendo este vídeo aqui do Filipe Deschamps. Ele explica como diminuir os if's no js. Mas, aí depende um pouco da linguagem também que você programa, e se ela teria uma alternativa a isso. Normalmente tem um jeito de diminuir.
Se você usar if's demais, o código pode ficar confuso e muito extenso. É uma boa prática diminuir eles. Mas, não significa que tá errado o código com vários dele. Só vai estar mal organizado, no máximo haha! Saber qual linguagem tu usa poderia ser útil para dar uma direção melhor sobre isso. Espero que eu consiga ajudar, ao menos um pouco 😉

1

Acredito que é melhor focar na prática e consumir conteúdo de gente boa programando. Com o tempo você vai entendendo onde cabe cada coisa.

1

Algumas implementacoes dependem muito da linguagem, mas em algumas estruturas tu pode utilizar mapa na estrutura chave:valor para armazenar um conjunto de dados que pode ser validado. Usei isso algumas vezes em Python e em Java.

Por exemplo, esse método em Java que recebe uma região como parametro, e retorna uma lista com a sigla de alguns estados da região:

	private ArrayList<String> getEstados(String regiao) {
	    if (regiao.equalsIgnoreCase("Sul")) {
		    return new ArrayList<>(Arrays.asList("RS", "SC", "PR"));
		} else if (regiao.equalsIgnoreCase("Sudeste")) {
		    return new ArrayList<>(Arrays.asList("SP", "RJ", "MG", "ES"));
		} else if (regiao.equalsIgnoreCase("Centro Oeste")) {
		    return new ArrayList<>(Arrays.asList("GO", "MS", "MT", "DF"));
		} else if (regiao.equalsIgnoreCase("Nordeste")) {
		    return new ArrayList<>(Arrays.asList("PE", "PB", "BA", "MA"));
		} else if (regiao.equalsIgnoreCase("Norte")) {
		    return new ArrayList<>(Arrays.asList("AM", "PA", "AC", "AP"));
		} 
		return null;
	}

Toda essa validação de if-else poderia ser alterada por:

static HashMap <String, ArrayList<String>> mapa = new HashMap<>();
    
	public static void main(String[] args) {
		mapa.put("Sul", new ArrayList<>(Arrays.asList("RS", "SC", "PR")));
		mapa.put("Sudeste", new ArrayList<>(Arrays.asList("SP", "RJ", "MG", "ES")));
		mapa.put("Centro Oeste", new ArrayList<>(Arrays.asList("GO", "MS", "MT", "DF")));
		mapa.put("Nordeste", new ArrayList<>(Arrays.asList("PE", "PB", "BA", "MA")));
		mapa.put("Norte", new ArrayList<>(Arrays.asList("AM", "PA", "AC", "AP")));
		
		System.out.println("Estados da regiao Sul: " + getEstados("Sul"));
	}
	
	private static ArrayList<String> getEstados(String regiao) {
	    return mapa.get(regiao);
	}

Neste caso acima, criamos um mapa, onde o campo chave é o nome da região, e o campo valor é a lista com as siglas dos estados. No novo metodo, apenas estamos verificando no mapa, para retornar o valor da chave referente a regiao (no caso ali, a "Sul").

Assim, implementamos a mesma lógica, sem usar nenhum if-else. Além disso, utilizando essa abordagem, seu código pode trabalhar com dados dinamicos.

No primeiro caso, o método getEstados está totalmente hardcoded, então se algum novo estado fosse adicionado na lista, teria que alterar o código fonte. No segundo caso, utilizando o mapa, mesmo que um novo estado (ou até mesmo regiao) fossem adicionados, não mudaria nada no método getEstados, tornando assim o código mais escalável e fácil de manter.

Neste segundo caso, somente seria necessário alterar o código se a estrutura em si do mapa, com a chave String e o valor ArrayList fossem alterados para algum outro tipo de dado.