Ejemplo de excepciones: "enviar un SMS"

Hace unos meses terminamos una aplicación de "trivias" (sistema de preguntas y respuestas) para celulares donde toda comunicación con el sistema se da a través de mensajes SMS.

Estimo que para sorpresa de muchos, está desarrollada enteramente en PHP5 + MySQL5, y se implementó un sistema en 3 capas para controlar toda la complejidad del sistema (que no era "trivial", el sistema está siendo usado para una campaña que aparece en televisión, publicidad impresa, web, etc e involucra marcas muy importantes, con un flujo enorme de usuarios participando lo que genera millones de mensajes).

Sé que en el mundo PHP no estamos tan acostumbrados a usar ni interfaces ni excepciones, así que me pareció oportuno comentar unos ejemplos extremadamente simples que pueden clarificar los beneficios de su uso.

Nuestra aplicación, como toda que trabaje con mensajes SMS, tiene un límite de 160 caracteres por mensaje, y para nuestro sistema, desbordar ese límite significa que existirán caracteres que se perderán (no es opcional enviar dos SMS en esa situación, el mensaje tiene que llegar al usuario en un solo SMS).

Por lo tanto, para la integridad de la aplicación debe poder saber en el mismo momento si ocurre esta situación "anómala" y tratar de resolverla de alguna forma.

A modo de ejemplo teórico
supongamos que nuestro sistema recupera de forma dinámica dos cadenas de texto, la primera es la presentación de la pregunta de la trivia (información de puntos, mensaje de aliento que se extrae de cientos de frases diferentes, etc) y la segunda parte será la pregunta en sí misma (nuevamente, una tabla con miles de preguntas que se obtienen al azar).

Definimos como regla que si ambas cadenas superan los 160 caracteres estamos delante de un problema "excepcional" que debemos resolver
, ya que -como comentamos anteriormente- no es solución ni cortar el mensaje, ni enviarlo en dos SMS o matar la aplicación y enviar información de log (ya que estamos en producción y el sistema tiene que responder al usuario a toda costa).

Determinamos que lo más importante es enviar la pregunta de la trivia y no tanto si una pregunta no llega con su primer parte informativa (se asume que la pregunta siguiente no entrará en una situación "excepcional"), por lo tanto podríamos hacer algo tan simple como:



/* [código del sistema] */

$informacion = $trivia->getMensajeInformativo();
$pregunta = $mensaje->getPreguntaSiguiente();

try{

Sms::enviar(
$informacion . $pregunta
);

}catch(Exception $e){

Sms::enviar(
$pregunta,
Sms::ENVIO_FORZADO
);

}


Lo que está entre medio de las llaves "try" es el código que puede fallar, dentro del envío de SMS revisa el tamaño del texto y si supera los 160 caracteres envía una excepción de esta forma (y de paso genera un log para poder tener registro de estas situaciones anómalas y solucionarlas a futuro):



/* [código del sistema] */

if(strlen($mensaje) > MAXIMO_TEXTO){

$error = 'Fallo grave, no pudo enviarse el SMS!';

Log::errorLog(__FILE__,__LINE__,$error);

throw new Exception($error);

}


El método enviar de Sms retorna una excepción, es capturada en un nivel más arriba y pasa a ejecutar un plan alternativo, enviar el mensaje SMS con solo la pregunta (fundamental para el juego de la trivia) y a su vez, en caso que pudiera ocurrir algún otro problema, activa una "bandera" de ENVIO_FORZADO (envía sin importar si tiene que cortar el texto).

Un punto interesante a tener en cuenta es el uso de constantes en la propia clase como para que ella misma "auto-documente" sus opciones posibles, ya que estoy ejecutando el método de la clase Sms pero a su vez uso la clase Sms para que me diga cuales son las opciones posibles y no tengo que estar recordando y/o investigando el código interno para colocar "números mágicos" del tipo 0,1,2,3, etc.


class Sms
{
const ENVIO_FORZADO = true;
const ENVIO_NORMAL = false;

/* [código de la clase] */
}


Nota: en este punto es importante destacar la función de un buen IDE, como podría ser Netbeans, que al teclear Sms:: nos mostrará toda la lista de opciones disponibles, entre ellas, las constantes.

También hay que tener en cuenta que es una situación "teórica" y a modo de ejemplo, ya que habría que implementar un sistema que controle los tamaños posibles de ambas frases, que la suma no supere 160 caracteres, si lo hace, que vuelva a solicitar una de las dos frases, etc. Para este ejemplo nos concentramos desde el punto de vista del enviador de mensajes, ya que a pesar que se hagan distintos controles para el mismo tema en cada capa, este tema igual lo tiene que poder contemplar la clase Sms.

Este ejemplo se puede profundizar, agregando distintos tipos de excepciones para cada tipo de error y solo forzar cuando es un error genérico, así "hilar más fino" y tratar de controlar la situación "excepcional".

3 comentarios:

proclamo dijo...

Una pregunta, ¿la interfície de usuario, en qué formato está? ¿web? ¿o habéis usado alguna librería especial para teléfonos?

Enrique Place dijo...

Estimado Proclamo:

Como el envío son SMS, lo único que se hace es enviar "texto plano" sin caracteres especiales (como ñ, etc) para que todos los celulares lo puedan representar sin problemas.

Esto sale por un "router" que es la aplicación que se encarga de enviar el mensaje a la operadora (carrier) correspondiente para ese celular y ser entregado al cliente.

No es complejo, imagina una aplicación que solo maneja textos hasta 160 caracteres y las respuestas generalmente son A, B, etc.

proclamo dijo...

Ah, vale, lo había entendido mal :P
Creí que era una aplicación instalada en el teléfono.

Entradas populares