He estado pensando en este tema por un tiempo y me gustaría tener opiniones de otros desarrolladores.
Tiendo a tener un estilo de programación muy defensivo. Mi bloque o método típico se ve así:
T foo(par1, par2, par3, ...)
{
// Check that all parameters are correct, return undefined (null)
// or throw exception if this is not the case.
// Compute and (possibly) return result.
}
Además, durante el cálculo, verifico todos los punteros antes de desreferenciarlos. Mi idea es que, si hay algún error y algún puntero NULL debería aparecer en alguna parte, mi programa debería manejarlo bien y simplemente negarse a continuar el cálculo. Por supuesto, puede notificar el problema con un mensaje de error en el registro o algún otro mecanismo.
Para decirlo de una manera más abstracta, mi enfoque es
if all input is OK --> compute result
else --> do not compute result, notify problem
Otros desarrolladores, entre ellos algunos colegas míos, utilizan otra estrategia. Por ejemplo, no verifican los punteros. Asumen que un código debe recibir la entrada correcta y no debe ser responsable de lo que sucede si la entrada es incorrecta. Además, si una excepción de puntero NULL bloquea el programa, se encontrará un error más fácilmente durante las pruebas y tendrá más posibilidades de ser reparado.
Mi respuesta a esto es normalmente: ¿pero qué pasa si el error no se encuentra durante las pruebas y aparece cuando el cliente ya está utilizando el producto? ¿Cuál es la forma preferida para que el error se manifieste? ¿Debería ser un programa que no realiza una determinada acción, pero que aún puede continuar funcionando, o un programa que se bloquea y necesita reiniciarse?
Resumiendo
¿Cuál de los dos enfoques para manejar una entrada incorrecta recomendaría?
Inconsistent input --> no action + notification
o
Inconsistent input --> undefined behaviour or crash
Editar
Gracias por las respuestas y sugerencias. Soy fanático del diseño por contrato también. Pero incluso si confío en la persona que ha escrito el código llamando a mis métodos (tal vez soy yo mismo), todavía puede haber errores, lo que lleva a una entrada incorrecta. Por lo tanto, mi enfoque es nunca suponer que un método pasa la entrada correcta.
Además, usaría un mecanismo para detectar el problema y notificarlo. En un sistema de desarrollo, por ejemplo, abriría un cuadro de diálogo para notificar al usuario. En un sistema de producción, solo escribiría alguna información en el registro. No creo que las comprobaciones adicionales puedan generar problemas de rendimiento. No estoy seguro de si las afirmaciones son suficientes, si se desactivan en un sistema de producción: tal vez ocurra alguna situación en la producción que no se haya producido durante las pruebas.
De todos modos, me sorprendió mucho que muchas personas sigan el enfoque opuesto: dejan que la aplicación se bloquee "a propósito" porque sostienen que esto hará que sea más fácil encontrar errores durante las pruebas.