C# - Usando Guard Clauses
Hoje veremos o conceito de Guard e como usar Guard Clauses para otimizar o seu código. |
O termo "guard" é frequentemente usado para se referir a uma técnica de programação que verifica condições de pré-condição em um método ou função.
Também conhecido como "guard clauses" ou "guard conditions", esse padrão de programação tem como objetivo verificar se as condições necessárias para a execução correta de um método são atendidas e, caso contrário, retornar ou lançar uma exceção antes de executar o restante do código.
Seguindo as diretrizes de programação defensiva e o design de sistemas fail-fast, um método deve sempre validar sua entrada.
O código que valida as entradas do seu método é chamado de Guard Clause ou cláusulas de Guarda, e, isso torna seu código mais compreensível e protege você de bugs e comportamentos inesperados.
Suponha que temos o código a seguir:
void ValidaAcesso() { if (Conexao) { if (Login) { if (Admin) { PainelAdmin(); } else { Console.WriteLine("Acesso restrito ao Admin"); } } else { Console.WriteLine("Precisa fazer Login"); } } else { Console.WriteLine("Sem conexão..."); } } |
Embora o código seja simples temos uma aninhamento de if/else que o torna difícil de ler. Além disso e um valor null for informado isso não esta sendo previsto e teremos um erro que vai quebrar o código.
Podemos melhora este código usando as Guard Clause separando as condições e invertendo a lógica da seguinte forma:
void ValidaAcesso() { if (!Conexao) { Console.WriteLine("Sem conexão..."); return; } if (!Login) { Console.WriteLine("Precisa fazer Login"); return; } if (!Admin) { Console.WriteLine("Acesso restrito ao Admin"); return; } PainelAdmin(); } |
O código agora ficou mais claro e fácil de entender classes ao uso das cláusulas de guarda.
Vejamos outro exemplo:
public bool ValidaUrl(string url) { return Uri.TryCreate(url, UriKind.Absolute, out Uri result) && (result.Scheme == "http" || result.Scheme == "https"); } |
Neste código se
passarmos null como o parâmetro url, o método retornará false. À primeira vista,
isso pode parecer correto, já que null é de fato uma URL inválida. No entanto,
essa não foi nossa intenção e não consideramos null um valor de entrada válido.
Assim, poderíamos reescrever o método como:
public bool ValidaUrl(string url) { if (url == null) throw new ArgumentNullException(nameof(url));
return Uri.TryCreate(url, UriKind.Absolute, out Uri result) &&
|
A expressão if que foi introduzida é uma Guard Clauses ou Cláusulas de Guarda e agora um valor null esta sendo previsto e tratado.
No entanto, podemos melhorar o código para não ficar repetido o código em nossos métodos ferindo assim o princípio DRY - Don´t repeate yourself. Para isso podemos criar uma classe estática e concentrar nela as validações.
public static class GuardClauses { public static void IsNotNull(object argumentValue, string argumentName) { if (argumentValue is null) throw new ArgumentNullException(argumentName); } } |
Agora o código ficaria assim:
public bool ValidaUrl(string url) { GuardClauses.IsNotNull(url, nameof(url));
return Uri.TryCreate(url, UriKind.Absolute, out Uri result) && |
No uso das
cláusulas de guarda a lógica das condições normalmente é invertida e, dependendo
da complexidade da condição, será muito complexo entender o que está sendo
avaliado naquela condição.
Por isso é uma boa prática extrair a lógica das condições em pequenas funções
que permitem maior legibilidade do código e, claro, encontrar bugs neles, já que
a responsabilidade de avaliar a condição está sendo delegada a uma função
específica.
Assim podemos criar mais métodos em nossa classe GuardClauses para atender outros critérios.
public static class GuardClauses { public static void IsNaoNull(object valorArgumento, string nomeArgumento) { if (valorArgumento is null) throw new ArgumentNullException(nomeArgumento); } public static void IsNaoNullOuVazio(string valorArgumento, string nomeArgumento) public static void IsNaoZero(int valorArgumento, string nomeArgumento) public static void IsMenorQue(int valorMaximo, int valorArgumento, string nomeArgumento) public static void IsMaiorQue(int valorMinimo, int valorArgumento, string nomeArgumento) |
Existem muitas técnicas para melhorar a qualidade do código. A coisa mais importante a aprender ao aplicar técnicas de refatoração é que elas devem ser focadas em dois pontos :
O uso de guard clauses pode ajudar a melhorar a legibilidade do código, evitando a necessidade de aninhamento excessivo de blocos "if" e tornando as pré-condições mais claras e explícitas.
E estamos conversados...
'Tendo sido,
pois, justificados pela fé, temos paz com Deus, por nosso Senhor Jesus
Cristo;'
Romanos 5:1
Referências:
ASP .NET - Gerando QRCode com a API do Google
C# 9.0 - Instruções de nível superior
ASP.NET Core - Usando o token JWT com o Swagger