Eu me pego escrevendo muitos códigos como este:
int myFunction(Person* person) {
int personIsValid = !(person==NULL);
if (personIsValid) {
// do some stuff; might be lengthy
int myresult = whatever;
return myResult;
}
else {
return -1;
}
}
Pode ficar bem confuso, principalmente se houver várias verificações. Nesses casos, experimentei estilos alternativos, como este:
int netWorth(Person* person) {
if (Person==NULL) {
return -1;
}
if (!(person->isAlive)) {
return -1;
}
int assets = person->assets;
if (assets==-1) {
return -1;
}
int liabilities = person->liabilities;
if (liabilities==-1) {
return -1;
}
return assets - liabilities;
}
Estou interessado em comentários sobre as escolhas estilísticas aqui. [Não se preocupe muito com os detalhes das declarações individuais; é o fluxo geral de controle que me interessa.]
coding-style
language-agnostic
William Jockusch
fonte
fonte
Respostas:
Para este tipo de questões, Martin Fowler propôs um padrão de especificação :
Acima parece um pouco exagerado (pelo menos para mim), mas quando eu tentei no meu código, ele foi bem tranquilo e ficou fácil de implementar e ler.
Na minha opinião, a idéia principal é "extrair" o código que faz as verificações nos métodos / objetos dedicados.
Com o seu
netWorth
exemplo, isso pode ter a seguinte aparência:Seu caso parece bastante simples, de modo que todas as verificações parecem OK para caber em uma lista simples em um único método. Muitas vezes, tenho que dividir para mais métodos para torná-lo melhor.
Eu também geralmente agrupo / extraio métodos relacionados "spec" em um objeto dedicado, embora seu caso pareça bom sem isso.
Esta pergunta no Stack Overflow recomenda alguns links além do mencionado acima: Exemplo de padrão de especificação . Em particular, as respostas sugerem o Dimecasts 'Learning the Specification pattern' para uma explicação passo a passo de um exemplo e mencionam o artigo "Specifications", de autoria de Eric Evans e Martin Fowler .
fonte
Acho mais fácil mover a validação para sua própria função; isso ajuda a manter a intenção de outras funções mais limpas; portanto, seu exemplo seria assim.
fonte
if
invalidPerson
? Simplesmente retorneperson!=NULL && person->isAlive && person->assets !=-1 && person->liabilities != -1
.Uma coisa que eu vi funcionar particularmente bem é a introdução de uma camada de validação no seu código. Primeiro, você tem um método que faz toda a validação confusa e retorna erros (como
-1
nos exemplos acima) quando algo dá errado. Quando a validação é concluída, a função chama outra função para fazer o trabalho real. Agora, essa função não precisa executar todas essas etapas de validação, porque elas já devem estar concluídas. Ou seja, a função de trabalho assume que a entrada é válida. Como você deve lidar com suposições? Você os afirma no código.Eu acho que isso torna o código muito fácil de ler. O método de validação contém todo o código confuso para lidar com erros do lado do usuário. O método de trabalho documenta claramente suas suposições com afirmações e não precisa trabalhar com dados potencialmente inválidos.
Considere esta refatoração do seu exemplo:
fonte