Me encuentro escribiendo mucho código 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;
}
}
Puede volverse bastante complicado, especialmente si hay varias comprobaciones involucradas. En tales casos, he experimentado con 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;
}
Me interesan los comentarios sobre las elecciones estilísticas aquí. [No se preocupe demasiado por los detalles de las declaraciones individuales; es el flujo de control general lo que me interesa.]
coding-style
language-agnostic
William Jockusch
fuente
fuente
Respuestas:
Para estos temas amables Martin Fowler propuso especificación del patrón :
Lo anterior suena un poco alto (al menos para mí), pero cuando lo probé en mi código, fue bastante sencillo y resultó fácil de implementar y leer.
A mi modo de ver, la idea principal es "extraer" el código que realiza las comprobaciones en métodos u objetos dedicados.
Con su
netWorth
ejemplo, esto podría verse de la siguiente manera:Su caso parece bastante simple para que todas las comprobaciones se vean bien y quepan en una lista simple dentro de un solo método. A menudo tengo que dividirme en más métodos para que se lea mejor.
También suelo agrupar / extraer métodos relacionados con "especificaciones" en un objeto dedicado, aunque su caso se ve bien sin eso.
Esta pregunta en Stack Overflow recomienda algunos enlaces además de uno mencionado anteriormente: Ejemplo de patrón de especificación . En particular, las respuestas sugieren Dimecasts 'Learning the Specification pattern' para un tutorial de un ejemplo y mencionan el documento "Especificaciones" escrito por Eric Evans y Martin Fowler .
fuente
Me resulta más fácil mover la validación a su propia función, ayuda a mantener limpia la intención de otras funciones, por lo que su ejemplo sería así.
fuente
if
envalidPerson
? Simplemente regreseperson!=NULL && person->isAlive && person->assets !=-1 && person->liabilities != -1
en su lugar.Una cosa que he visto funcionar particularmente bien es la introducción de una capa de validación en su código. Primero tiene un método que hace toda la validación desordenada y devuelve errores (como
-1
en sus ejemplos anteriores) cuando algo sale mal. Cuando se realiza la validación, la función llama a otra función para hacer el trabajo real. Ahora esta función no necesita hacer todos esos pasos de validación porque ya deberían estar hechos. Es decir, la función de trabajo supone que la entrada es válida. ¿Cómo debe lidiar con los supuestos? Los afirmas en el código.Creo que esto hace que el código sea muy fácil de leer. El método de validación contiene todo el código desordenado para tratar los errores del lado del usuario. El método de trabajo documenta limpiamente sus supuestos con afirmaciones y luego no tiene que funcionar con datos potencialmente inválidos.
Considere esta refactorización de su ejemplo:
fuente