6 maneiras de fazer a mesma coisa, o que é considerado boas práticas?

As vezes tem tantas maneiras diferentes de fazer o mesmo código que nós ficamos na dúvida quanto a qual maneira usar. O que seria considerado "boa prática" pela comunidade e o que sua equipe entenderia melhor.

Suponhamos que você esteja trabalhando dentro de um método de um Domain Service chamado UmDomainServiceChique(objetoDoDominio) que será chamado por uma API.

Você tem uma regra de negócio chique para ser verificada que por enquanto chamarei de VerificaMinhaRegraChiqueComplexa().

Você chama UmDomainServiceChique(objetoDoDominio) e caso VerificaMinhaRegraChiqueComplexa() retorne true você vai querer que UmDomainServiceChique faça o que tem que fazer e a api retornar Ok 200, caso contrário você quer que a API responda um erro qualquer, tipo BadRequest, e retornar uma mensagem dizendo que VerificaMinhaRegraChiqueComplexa deu ruim.

Eu vejo 6 maneiras de fazer isso, gostaria de saber a opinião de outrs devs sobre qual seria a maneira menos gambiarrística de fazer:

1) se VerificaMinhaRegraChiqueComplexa() for false disparo uma exception. Eu particularmente não gosto disso porque exceptions são lentas e quebram o fluxo de execução do sistema. Acho sujo.


namespace MeuBreguetz.DomainServices
{
	public class MeuDomainService()
	{
		public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio) 
		{
			return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
		}
		
		public void UmDomainServiceChique(Obeeeeejeto objetoDoDominio)
		{
			if(VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
			{
				//faz o que tem q fazer boneeeeto
				//salva
			}
			else
			{
				throw new MinhaExceptionZuada("Deu ruim porque a regra chique não valeu");
			}
		}
	}
}
namespace MeuBreguetz.API
{
	public class MinhaApi
	{
		public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
		{
			//...
			svc.UmDomainServiceChique(objeeeeeto);
			return Ok();
		}
	}
}

2) retornar um boolean e um out parameter string com mensagem de erro. Eu não gosto de out parâmeters


namespace MeuBreguetz.DomainServices
{
	public class MeuDomainService()
	{
		public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio) 
		{
			return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
		}
		
		public bool UmDomainServiceChique(Obeeeeejeto objetoDoDominio, out string mensagem)
		{
			mensagem = "";
			if(VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
			{
				//faz o que tem q fazer boneeeeto
				//salva
				return true;
			}
			else
			{
				mensagem = "Deu ruim porque a regra chique não valeu";
				return false;
			}
		}
	}
}
namespace MeuBreguetz.API
{
	public class MinhaApi
	{
		public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
		{
			//...
			if (svc.UmDomainServiceChique(objeeeeeto, out string mensagem))
			{
				return Ok();
			}
			else{
				return BadRequest(mensagem);
			}
		}
	}
}

3) retornar void com dois out parameters, um boolean e um string com a msg de erro. Eu sempre tenho essa dúvida quando se trata de dois outputs: uso o return do método mais um parâmetro ou faço método void com dois parâmetros ?


namespace MeuBreguetz.DomainServices
{
	public class MeuDomainService()
	{
		public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio) 
		{
			return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
		}
		
		public void UmDomainServiceChique(Obeeeeejeto objetoDoDominio, out bool sucesso, out string mensagem)
		{
			mensagem = "";
			sucesso = true;
			if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
			{
				sucesso false;
				mensagem = "Deu ruim porque a regra chique não valeu";
				return; //ou não ....
			}
			
			//else ... dependendo da regra 
			
			//faz o que tem q fazer boneeeeto
			//salva
		}
	}
}
namespace MeuBreguetz.API
{
	public class MinhaApi
	{
		public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
		{
			//...
			svc.UmDomainServiceChique(objeeeeeto, out bool sucesso, out string mensagem);
			
			if (sucesso)
			{
				return Ok();
			}
			else{
				return BadRequest(mensagem);
			}
		}
	}
}

4) retornar um value tuple. Eu particularmente não gosto de tuples do tipo Tuple por causa dos nomes Item1, Item2 ... e também não curto a sintaxe nova dos value tuples nomeados, acho bagunçado e acho que poucos membros no time entendem essa sintaxe nova.


namespace MeuBreguetz.DomainServices
{
	public class MeuDomainService()
	{
		public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio) 
		{
			return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
		}
		
		public (bool Sucesso, string Mensagem) UmDomainServiceChique(Obeeeeejeto objetoDoDominio) //vc fica com mais itens antes do nome do que depois, muito estranho
		{
			if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
			{
				return (false, "Deu ruim porque a regra chique não valeu");
			}
			
			//faz o que tem q fazer boneeeeto
			//salva
			return (true, "");
		}
	}
}
namespace MeuBreguetz.API
{
	public class MinhaApi
	{
		public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
		{
			//...
			var resultado = svc.UmDomainServiceChique(objeeeeeto);
			
			if (resultado.sucesso)
			{
				return Ok();
			}
			else{
				return BadRequest(resultado.mensagem);
			}
		}
	}
}

5) retornar um um DTO. Aí mais cedo ou mais tarde sua aplicação fica cheia de DTOs e você se encontra no inferno. Eles se espalham, e uma hora tomam a aplicação inteira.


namespace MeuBreguetz.DomainServices
{
	public class InteligentíssimoDtoDeResultado
	{
		//aqui, a meu ver, tanto faz ser classe ou struct, imutável ou não, usar backed properties ou fields públicos ... dá no mesmo
		public bool Sucesso {get; set;}
		
		public string Mensagem {get; set;}
	}
	
	public class MeuDomainService()
	{
		public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio) 
		{
			return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
		}
		
		public InteligentíssimoDtoDeResultado UmDomainServiceChique(Obeeeeejeto objetoDoDominio) //vc fica com mais itens antes do nome do que depois, muito estranho
		{
			if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
			{
				return new InteligentíssimoDtoDeResultado {Sucesso = false, Mensagem = "Deu ruim porque a regra chique não valeu"};
			}
			
			//faz o que tem q fazer boneeeeto
			//salva
			return new InteligentíssimoDtoDeResultado {Sucesso = true};
		}
	}
}
namespace MeuBreguetz.API
{
	public class MinhaApi
	{
		public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
		{
			//...
			var resultado = svc.UmDomainServiceChique(objeeeeeto, out bool sucesso, out string mensagem)
			
			if (resultado.Sucesso)
			{
				return Ok();
			}
			else{
				return BadRequest(resultado.Mensagem);
			}
		}
	}
}

6) retornar um dynamic contendo um objeto anônimo e ver o mundo pegar fogo, perder todos os benefícios da checagem de tipo em design time


namespace MeuBreguetz.DomainServices
{
	
	public class MeuDomainService()
	{
		public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio) 
		{
			return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
		}
		
		public dynamic UmDomainServiceChique(Obeeeeejeto objetoDoDominio) //vc fica com mais itens antes do nome do que depois, muito estranho
		{
			if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
			{
				return new {Sucesso = false, Mensagem = "Deu ruim porque a regra chique não valeu"};
			}
			
			//faz o que tem q fazer boneeeeto
			//salva
			return new {Sucesso = true};
		}
	}
}
namespace MeuBreguetz.API
{
	public class MinhaApi
	{
		public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
		{
			//...
			var resultado = svc.UmDomainServiceChique(objeeeeeto, out bool sucesso, out string mensagem)
			
			if (resultado.Sucesso)
			{
				return Ok();
			}
			else{
				return BadRequest(resultado.Mensagem);
			}
		}
	}
}

E aí? vamos votar?

Diga aí nos comentários, 1,2,3,4,5,6 ?

Comentários

Postagens mais visitadas deste blog

Uso de memória no SQL Server

Busca de CEP com o Lazarus - Parte 1 - UrlEncode

Botão Add This para adicionar seu post em qualquer rede