Repaso sobre Exceptions

Pueden ver un apunte completo en este link

He aquí unas notas o agregados al documento.

Manejar una exception es:

  • Propagarla
    • Cuando no se cómo salvar la situación.
    • Dos formas:
      • propago la misma exception (declarando throws XXXException en la firma del método).
      • wrappeándola: envolviéndola en otra nueva, que agregará un mensaje de más alto nivel. Ej:
    public void enviarResumenMensual(Cliente c) {
        try {
            String resumen = this.generador.crearResumen(c);
            this.clienteMail.enviarMail(c.getEmail(), resumen);
        } catch (EmailException e) {
            throw new ProgramException("Error al enviar el resumen por mail al usuario " + c.getNombre(), e);
        }
    }
  • Tratarla:
    • Cuando tengo un requerimiento específico como:
      • Si falla el servidor de mail, intentar con una lista de otros servidores alternativos.
      • Si falla el servidor de mail, esperar 5 segundos y reintentar. Realizar esto unas 5 veces. Caso que siga fallando, abortar el envío con un mensaje. 

Buenas Prácticas

  • Nunca catchear una exception para no hacer nada. No hacer nada también incluye el "loggearla". Es decir, catchear para loggear y seguir adelante, debería sonar muy raro. Tal vez tenga sentido eso como requerimiento en un único lugar de la arquitectura, para que no se caiga completamente la aplicación. Pero en el 99% de las veces es una hackeada.
  • No catchear excepciones muy genéricas como Exception o Throwable.
    • De nuevo, esto quizás solo aplique a un lugar muy puntual de la arquitectura. Pero en el 99% de los casos uno no debe "catchear cualquier cosa", sino exceptions paticulares.
  • No catchear y "comerse" el error:
    • Ya lo dijimos arriba, pero lo repetimos.
  • En general wrappear para agregar información de contexto (qué estaba haciendo este método al encontrar un error en otro al que llama)
    • Así al momento de fallar una operación de negocio no terminamos con un solo mensaje puntual muy específico que será dificil de comprender para el usuario/administrador/programador, como "No me pude conectar al host 12.23.22.12", si no una jerarquía de mensajes desde lo más general a lo más específico como: "Error al ejecutar el ciclo de facturación -> Error al facturarle al usuario numero 5963472 -> Error al enviar el resumen mensual -> Error al enviar el mail -> No me pude conectar al host 12.23.22.12"
  • Nunca comerse la causa al wrappear (en nuestro ejemplo, la referencia a través de la variable e)
  • Evitar try-catch dentro de otro try-catch: refactorizar la parte interna que puede fallar, llevándola a otro submétodo.
  • Intentar evitar código antes y después de un try-catch, llevando todo el código a la forma, método() { try { logica } catch }. Es decir que el try-catch envuelva "todo" el código del método. Este va de la mano con la idea de hacer métodos más chiquitos. Al hacer una sola cosa, el método solo puede tener un tipo de falla.