Eu tenho alguns métodos que executam algumas alterações de dados em um banco de dados (inserir, atualizar e excluir). O ORM que estou usando retorna valores int afetados por linha para esse tipo de método. O que devo retornar para "meu método", a fim de indicar o estado de sucesso / falha da operação?
Considere o código que está retornando um int
:
A.1
public int myLowerLevelMethod(int id) {
...
int affectedRows = myOrm.deleteById(id)
...
return affectedRows;
}
Então uso:
A.2
public void myOtherMethod() {
...
int affectedRows = myLowerLevelMethod(id)
if(affectedRows > 0) {
// Success
} else {
// Fail
}
}
Compare com o uso de booleano:
B.1
public boolean myLowerLevelMethod(int id) {
...
int affectedRows = myOrm.deleteById(id)
...
return affectedRows > 0;
}
Então uso:
B.2
public void myOtherMethod() {
...
boolean isSuccess = myLowerLevelMethod(id)
if(isSuccess) {
// Success
} else {
// Fail
}
}
Qual (A ou B) é melhor? Ou prós / contras de cada um?
design
error-handling
methods
Hoang Tran
fonte
fonte
Respostas:
Outra opção é retornar um objeto de resultado em vez de tipos básicos. Por exemplo:
Com isso, se, por algum motivo, você precisar retornar o número de linhas afetadas, basta adicionar um método em OperationResult:
Esse design permite que seu sistema cresça e inclua novas funcionalidades (conhecimento sobre as linhas afetadas) sem modificar o código existente.
fonte
Retornar o número de linhas afetadas é melhor porque fornece informações adicionais sobre como a operação prosseguiu.
Nenhum programador o culpará porque ele / ela deve escrever isso para verificar se houve algumas alterações durante a operação:
mas eles o culparão quando precisarem saber o número de linhas afetadas e perceberem que não há método para obter esse número.
BTW: se por "falha" você quer dizer um erro de consulta sintática (nesse caso, o número de linhas afetadas é obviamente 0), lançar a exceção seria mais apropriado.
fonte
update t set category = 'default' where category IS NULL
até 0 linhas afetadas seria um sucesso, porque agora não há item sem categoria, mesmo que nenhuma linha tenha sido afetada!Eu não recomendaria nenhum deles. Em vez disso, não retorne nada (nulo) ao sucesso e lance uma exceção ao falhar.
É exatamente pelo mesmo motivo que escolhi declarar certos membros da classe como particulares. Também torna a função mais fácil de usar. Contexto mais operacional nem sempre significa melhor, mas certamente significa mais complexo. Quanto menos você promete, quanto mais abstrai, mais fácil é para o cliente entender e mais liberdade você tem para escolher como implementá-lo.
A questão é como indicar sucesso / erro. Nesse caso, basta sinalizar a falha lançando uma exceção e não retornando nada com êxito. Por que tenho que fornecer mais do que o usuário precisa?
Falhas / situações excepcionais podem acontecer e você terá que lidar com elas. Se você usa try / catch para fazer isso ou examina os códigos de retorno, é uma questão de estilo / preferência pessoal. As idéias por trás do try / catch são: separar o fluxo normal do fluxo excepcional e permitir que as exceções borbulhem até a camada em que possam ser tratadas da maneira mais adequada. Portanto, como muitos já apontaram, depende se a falha é realmente excepcional ou não.
fonte
"Isso é melhor que isso?" Não é uma pergunta útil quando as duas alternativas não fazem a mesma coisa.
Se você precisar conhecer a contagem de linhas afetadas, deverá usar a versão A. Se não precisar, poderá usar a versão B - mas qualquer vantagem que possa obter em termos de menos esforço para escrever código já desapareceu desde você teve o trabalho de publicar as duas versões em um fórum online!
O que quero dizer é: qual solução é melhor depende inteiramente de quais são seus requisitos especificamente para este aplicativo e você conhece essas circunstâncias muito melhor do que nós. Não existe uma opção de mercado, prática segura, prática recomendada, que não seja demitida sobre ela que seja melhor em geral ; você tem que pensar sobre isso sozinho. E para uma decisão tão facilmente revisada quanto esta, você também não precisa gastar tanto tempo pensando.
fonte
Dois dos princípios mais importantes no design de software sustentável são o KISS e o YAGNI .
Quase nunca é uma boa idéia colocar na lógica que você não precisa imediatamente no momento . Entre muitas outras pessoas, Jeff Atwood (co-fundador do StackExchange) escreveu sobre isso e, na minha experiência, ele e outros defensores desses conceitos estão completamente certos.
Qualquer complexidade que você adicionar a um programa tem um custo, pago por um longo período de tempo. O programa se torna mais difícil de ler, mais complexo para alterar e mais fácil para os bugs aparecerem. Não caia na armadilha de adicionar coisas "apenas por precaução". É uma falsa sensação de segurança.
Você raramente consegue obter um código correto da primeira vez. Mudanças são inevitáveis; adicionar lógica especulativa para se preparar defensivamente para contingências futuras desconhecidas não o protegerá de refatorar seu código quando o futuro for diferente do esperado. A manutenção de lógicas desnecessárias / contingentes é mais um problema de manutenção do que refatorar posteriormente para adicionar a funcionalidade ausente.
Portanto, como parece que tudo o que seu programa precisa agora é saber se a operação foi bem-sucedida ou falhou, a solução proposta B (retornar um único booleano) é a abordagem correta. Você sempre pode refatorá-lo mais tarde se o requisito for alterado. Esta solução é a mais simples e tem a menor complexidade (KISS) e faz exatamente o que você precisa e nada mais (YAGNI).
fonte
As linhas inteiras ou um status de erro
Considere retornar as linhas inteiras, pelo menos como uma opção de tempo de execução. Nas inserções de banco de dados, talvez seja necessário inspecionar os dados que foram inseridos - pois geralmente serão diferentes do que você enviou para o banco de dados; exemplos comuns incluem IDs de linha gerados automaticamente (que o aplicativo provavelmente precisará imediatamente), valores padrão determinados pelo DB e resultados de acionadores, se você os usar.
Por outro lado, se você não precisar dos dados retornados, também não precisará da contagem de linhas afetadas, pois não é útil para o resultado de 0. Se houver erros, será necessário retornar que tipo de ocorreu um erro, de maneira consistente com os princípios de tratamento de erros do seu projeto (exceções, códigos de erro numéricos, qualquer que seja); mas há consultas válidas que afetarão corretamente 0 linhas (por exemplo, "excluir todos os pedidos expirados", se realmente não houver).
fonte