Recientemente comencé a agregar algunas afirmaciones a mi código, y así es como lo he estado haciendo:
Divido mentalmente mi código en código de límite y código interno. El código de límite es un código que maneja la entrada del usuario, lee archivos y obtiene datos de la red. En este código, solicito la entrada en un bucle que solo sale cuando la entrada es válida (en el caso de la entrada interactiva del usuario), o lanzo excepciones en el caso de datos corruptos de archivos / redes irrecuperables.
El código interno es todo lo demás. Por ejemplo, una función que establece una variable en mi clase podría definirse como
void Class::f (int value) {
assert (value < end);
member = value;
}
y una función que recibe información de una red podría leerse como tal:
void Class::g (InMessage & msg) {
int const value = msg.read_int();
if (value >= end)
throw InvalidServerData();
f (value);
}
Esto me da dos capas de cheques. Cualquier cosa en la que los datos se determinen en tiempo de ejecución siempre recibe una excepción o un manejo inmediato de errores. Sin embargo, ese chequeo adicional Class::f
con la assert
declaración significa que si alguna vez llama un código interno Class::f
, todavía tengo un chequeo de cordura. Es posible que mi código interno no pase un argumento válido (porque puedo haber calculado a value
partir de una serie compleja de funciones), por lo que me gusta tener la afirmación en la función de configuración para documentar que, independientemente de quién llame a la función, value
no debe ser mayor que o igual a end
.
Esto parece encajar en lo que estoy leyendo en algunos lugares, que las afirmaciones deberían ser imposibles de violar en un programa que funcione bien, mientras que las excepciones deberían ser para casos excepcionales y erróneos que todavía son posibles. Debido a que, en teoría, estoy validando todas las entradas, no debería ser posible que se active mi afirmación. Si es así, mi programa está equivocado.
reflect.DeepEqual
, ciertamente no lo necesitas . Es conveniente, pero a costa del rendimiento (las pruebas unitarias son un buen caso de uso). De lo contrario, puede implementar cualquier verificación de igualdad que sea apropiada para su "colección" sin demasiados problemas.for
bucle en Go (al igual que C). Se podría ser muy bueno tener operaciones rebanada genéricos, aunque la comparación se complica cuando los punteros y las estructuras son los involucrados.