viernes, 17 de enero de 2014

Errores de diseño – Tipos fecha/hora

Recientemente tuve la oportunidad de realizar una actividad en una empresa de construcción. Se me contrató para realizar reportes sobre una base de datos que está en funcionamiento desde hace seis años.

Una de las tablas –que llamaremos actividad- tiene tres campos: «Hora de llegada», «hora de atención» y «hora de salida». Estas variables almacenan la hora en la cual una persona llega al lugar, la hora en la cual la atienden y la hora en la que se marcha del lugar. Para calcular el tiempo de espera se resta la «hora de llegada» de la «hora de atención» y para calcular el tiempo de atención se resta la «hora de atención» de la «hora de salida». El tiempo de permanencia se obtiene restando la «hora de llegada» de la «hora de salida».

La fecha en la que se espera realizar la actividad se almacena en la variable «hora de actividad». Esta variable, a diferencia de las otras no sólo almacena la hora sino también la fecha. Dicho de otra manera, la variable «hora de actividad» es de tipo «fecha/hora». La tabla -implantada bajo PostgreSQL- tiene la siguiente configuración (Se omite el resto de los campos).

CREATE TABLE actividad (

hora_de_actividad timestamp without time zone,

hora_de_llegada time without time zone,

hora_de_atencion time without time zone,

hora_de_salida time without time zone

);

Al generar los primeros reportes llamó mi atención el hecho de que muchos de los tiempos calculados eran negativos. Ahí detecté un gran problema: La compañía que diseñó la base de datos supuso que la hora de llegada, la hora de atención y la hora de salida ocurrían el mismo día en el que ocurría la hora de actividad, por lo tanto sólo se almacenaba en estas tres variable la hora en la que ocurrió cada evento.

Craso error.

Muchas actividades duran más de un día: Una persona puede llegar a las nueve de la noche del primer día, ser atendido a la tres de la mañana del segundo día e irse a la una de la mañana del tercer día... o de cualquier otro día. Seguidamente muestro un ejemplo:



ActividadLlegadaAtenciónSalidaEsp.Atn.Per.
2013-01-01 05:00:0021:00:0003:00:0001:00:00-18h-2h-20h
2013-01-01 05:00:0016:00:0017:00:0018:00:001h1h2h

El primer registro indica que alguien fue atendido a las tres de la mañana (de cualquier día, no necesariamente del día después de la actividad) y se marchó a la una de la mañana (de cualquier otro día). Ya que no se conoce la fecha de cada uno de los eventos posteriores a la llegada de una persona es imposible saber con exactitud los tiempos de permanencia, espera y atención. Incluso en el segundo registro, los tiempos de espera no son exactos: Basado en la lógica del negocio, la persona pudo haber llegado a las cuatro de la tarde del tres de enero, ser atendida a las cinco de la tarde del cuatro de enero y marcharse a las seis de la tarde del cinco de enero o de cualquier otro día; de esta manera los cálculos son erróneos.

Otro inconveniente de este diseño es que no es posible saber si la reunión comenzó antes o después de la hora planteada. Explicados estos detalles al cliente, esta fue su solución:

  • Suponer que la persona llegó el mismo día en el que fue planteada la reunión.
  • Suponer que la reunión comenzó el día en el que se definió.
  • Si la hora de atención es menor que la hora de llegada, suponer que la hora de atención ocurrió el día después en el que la reunión se definió. En caso contrario, la hora de atención y la hora de llegada ocurrieron el mismo día en el que la reunión se definió.
  • Hacer lo mismo con «hora de salida» y «hora de atención», pero en este caso, tomar como base el cálculo realizado en el punto anterior.
Como se observa, los reportes muestran «esa realidad» pero no lo que realmente ocurrió. Según el cliente los registros en dicha condición eran pocos, sin embargo, al calcular los promedios generales discriminados por gerencia, muchos tiempos resultaban negativos, así que el fenómeno se repetía más de lo esperado.

Más allá del error de tener en la tabla un campo para cada evento (violación de la primera forma normal), el principal inconveniente de este diseño es la pérdida de información ya que no es posible calcular con exactitud los tiempos en dicha base de datos.

Solución para el problema: Usar siempre tipos fecha/hora para evitar ambigüedades. En el caso de este cliente, es imposible recuperar la información de manera exacta. Un fallo tan «pequeño» en el diseño resultó en un gran inconveniente.

Cero para la consultora.

No hay comentarios: