sábado, 25 de mayo de 2013

Filtros de Tomcat - Parte I

Supongamos por un momento que es necesario cortar un árbol y se poseen las siguientes herramientas: un Hacha y un Serrucho.

¿Cuál herramienta es la más eficiente?

La mayoría de las personas considerarán el serrucho como la más eficiente. ¿Por qué? Básicamente porque todos conocemos las capacidades de un serrucho y podemos compararla con el hacha. Supongamos ahora que no conocemos ninguna de las herramientas y debemos elegir. La elección no es tan simple porque no conocemos las capacidades de cada una. El sentido común no nos permitiría hacer una elección correcta tampoco.

Lo anterior es un ejemplo muy simple de lo importante que es conocer (y tener) las herramientas adecuadas para realizar una tarea.

Hace algunas semanas atrás, un cliente solicitó una modificación a uno de los productos de la empresa en la que trabajo. La modificación implicaba modificar todas las páginas .jsp de la aplicación y, obviamente, había un plazo que cumplir, por lo que, la intervención manual de todas las páginas no era una opción. Había que buscar otra alternativa. ¿La solución? Filtros de Tomcat.  

1. Filtros de Tomcat
El servidor web Apache Tomcat provee una infraestructura denominada Filtros que permite interceptar el flujo de entrada y salida desde y hacia una página (.jsp) e intervenirlo. La gracia es que el filtro se programa una vez y permite realizar la tarea en todas las páginas existentes en el contexto.

La infraestructura de filtros está disponible desde la Servlet API 2.3 y fue mejorada en la versión 2.4, permitiendo que los filtros sean aplicados incluso en el traspaso de las solicitudes entre las páginas (por medio de las directivas forward o include). Los diagramas siguientes muestran cómo operan los filtros en el flujo de procesamiento de una página en las dos versiones.



2. Ejemplos de Filtros
Considerando el flujo anterior, un Filtro se puede construir para realizar diversas tareas. Algunos ejemplos simples son los siguientes:
  • Validaciones de Seguridad. Validar que cada página cumpla una condición determinada, por ejemplo, que el usuario esté autenticado.
  • Compresión de Salidas/Entradas. Comprimir un archivo automáticamente para minimizar el tiempo de descarga.
  • Registro de Eventos. Generar un log de auditoría respecto con la información de los accesos a las páginas de la aplicación.
  • Modificación/Intervención de Salidas/Entradas. Eliminación de caracteres especiales, sobrantes, limpieza de HTML, etc.
La implementación de un filtro implica las siguientes actividades:
  • Construcción de la clase que implementará el filtro con la funcionalidad deseada.
  • Configuración del filtro en Tomcat para que realice su tarea
Obviamente, la construcción del filtro debe realizarse primero que la configuración, sin embargo, voy a describir la configuración primero porque es relevante para entender el "encadenamiento" de los filtros en el procesamiento y la construcción correspondiente.

3. Configuración del Filtro
La configuración del filtro se realiza en el archivo web.xml del contexto (dentro de la carpeta WEB-INF/). Se debe agregar una configuración como la siguiente para cada filtro que se quiera habilitar:

<filter>
  <filter-name>NOMBRE</filter-name>
  <filter-class>CLASE</filter-class>
  <init-param>
    <param-name>PARAM_1</param-name>
    <param-value>VALOR_1</param-value>
  </init-param>

  :
  <init-param>
    <param-name>PARAM_n</param-name>
    <param-value>VALOR_n</param-value>
  </init-param>
</filter>


<filter-mapping>
  <filter-name>NOMBRE</filter-name>
  <url-pattern>PATRON</url-pattern>
</filter-mapping>


3.1 Sección <filter>.
Permite configurar un filtro en el contexto.
  • NOMBRE. Corresponde a un nombre lógico que identifica la acción/objetivo que realiza el filtro. Por ejemplo: LoginFilter, RegExFilter, HitCountFilter, etc.
  • CLASE. Corresponde al nombre de la clase que implementa el filtro. Obviamente, debe ser una clase que esté disponible para el contexto de la aplicación.
  • PARAM_i y VALOR_i. Se pueden agregar parámetros de configuración relevantes para el filtro agregando nodos del tipo <init-param>. Cada nodo contiene un nombre (PARAM_i) y un valor (VALOR_i).
3.2 Sección <filter-mapping>.
Permite configurar a qué páginas se aplicará el filtro.
  • NOMBRE. Corresponde al nombre lógico del filtro que se indicó en la sección anterior. Debe ser el mismo para que aplique correctamente.
  • PATRON. Corresponde al patrón de páginas para las cuales se desea que se aplique el filtro. Un ejemplo es /* que indica que aplica a todas las páginas del contexto.
Un aspecto importante de la configuración en el archivo web.xml es que el orden en el que se declaran los filtros. Por ejemplo, supongamos que tenemos dos filtros: HitCountFilter y LoginFilter. El primero registra el número de accesos a las páginas del sitio y el segundo valida que un usuario esté autenticado. Veamos dos configuraciones posibles en el web.xml:


La configuración a) implica que primero se registrarán los accesos y luego se validará al usuario. La configuración b) implica que primero se validará al usuario y luego se registrarán los accesos.

Lo anterior se denomina encadenamiento de filtros (Filter Chain) y establece el orden en el que se deben aplicar los filtros. Lo importante de esto es que los filtros se aplican en cadena sobre la entrada y, luego, de manera inversa sobre la salida. Considerando el ejemplo a) anterior, se produce la siguiente secuencia:


La entrada (E1) es recibida y procesada por HitCounter. El resultado (E2) es entregado a LoginFilter quien la procesa. El resultado (E3) es entregado a la página.jsp para su procesamiento. A esta altura, la ejecución de la página.jsp es similar a la ejecución que se realizaría si no hubiera filtros configurados, es decir, la página.jsp se programa como una página normal, independiente de los filtros que podrían haber sido configurados previamente. El flujo de salida opera de la misma manera permitiendo realizar acciones sobre el resultado (output) de la página.jsp. Ejemplos de acciones posibles a este nivel son la compresión del HTML (eliminando espacios en blanco) o el reemplazo de contenido por otro utilizando expresiones regulares.

4. Construcción del Filtro 
Un filtro se construye heredando de la clase javax.servlet.Filter y, en él, se deben implementar tres métodos:
  • init(FilterConfig filterConfig).
    Este método se ejecuta cuando el contexto es cargado por el servidor y sólo se ejecuta una vez. El parámetro filterConfig permite acceder a las configuraciones que se hayan realizado para el filtro en el archivo web.xml por medio de la secciones <init-param/>. 
  • doFilter(ServletRequest request, ServletResponse response, FilterChain chain).
    Este método se ejecuta cuando se requiere aplicar el filtro a la entrada (request) y a la salida (response). El parámetro chain es el que permite traspasar el control al siguiente filtro en la cadena. En casos específicos, se puede interrumpir el flujo programáticamente. Por ejemplo, si el filtro LoginFilter identifica que el usuario no está autenticado, no es necesario ejecutar la página .jsp correspondiente.
  • destroy(). Este método se ejecuta cuando se baja el contexto y puede/debe ser utilizado para liberar recursos que se hayan utilizado para la operación del filtro. Por ejemplo, cachés, contadores, etc.
En la próxima parte describiré un ejemplo práctico de cómo hacer un filtro de autenticación de usuarios que permita validar, de una manera simple y centralizada, que el acceso a las páginas lo realicen únicamente usuarios que se hayan autenticado correctamente.

viernes, 17 de mayo de 2013

Servicios Tecnológicos o Tecnología a su Servicio

Hace algunos días atrás fui a almorzar a un restaurant italiano que está cerca del Hotel Plaza San Francisco en la Alameda (más pistas no puedo dar por ahora). Era la primera vez que iba a ese local, previamente había ido a otros locales en otras partes de Santiago.

Al entrar al local, lo primero que me llamó la atención fue lo que se puede apreciar en la siguiente foto:


Efectivamente, un iPad al borde de cada mesa. Al principio miré con sorpresa esta situación y recorrí todo el local para ver si, efectivamente, todas las mesas tenían uno. Y, bueno, todas las mesas tenían lo mismo: un atril telescópico tipo micrófono, un soporte de metal para el iPad y un cable de corriente que, curiosamente, estaba "integrado" al iPad por la parte posterior. Cuando digo integrado me refiero a que el iPad tenía un agujero en la parte posterior por el cual entraba el cable. No había ninguna posibilidad de desconectarlo de la corriente, a menos que se rompiera o cortara el cable, como hubiera sido posible en el caso de la alimentación tradicional a través del Dock Connector.

Me senté en la mesa y comencé a apretar los botones. En la pantalla aparecía un teclado tipo calculadora que, obviamente, era la clave para habilitar la estación. Como ninguna clave me funcionó, y no me atendían, comencé a buscar mi plato en el menú. En las primeras páginas del menú aparecía una descripción del nuevo sistema, llamado Garzón Virtual desarrollado por la empresa D2 PAD. En ella, se indicaba cómo se debía utilizar, las funcionalidades básicas, ventajas, etc., ninguna de las cuales pude experimentar.

Después de un buen rato, se acercó un garzón y me tomó el pedido. Le pregunté por qué no lo podía hacer por el sistema y me indicó, literalmente, "sólo lo usamos para pedir la cuenta". Se fue con el pedido y dejó el iPad como estaba, es decir, bloqueado. Me puse a jugar con mi iPhone mientras me esperaba el almuerzo. Cuando terminé de almorzar, le hice un gesto a otro garzón, indicándole que necesitaba la cuenta. Volvió unos minutos después con la cuenta y el POS transbank para el pago con tarjeta. Pagué siguiendo el protocolo de seguridad para evitar clonación de tarjetas y luego me fui. El iPad no lo utilizaron nunca en mi presencia.

Hay dos cosas que me llamaron la atención de este sistema, como describo a continuación.

Inversión Tecnológica
En el local debe haber unas 180 mesas. Si cada mesa tiene un iPad, estamos hablando de una inversión aproximada de $44 millones de pesos o US$ 91.000, aproximadamente. Esto considerando el modelo más barato del iPad y sin considerar los "costos" adicionales de implementación (atril, cable, etc.). Si consideramos esto, el costo total debiera bordear los US$ 100.000.

Ahora bien, en el local debe haber unos 50 mozos. Si consideramos el hecho de que, obviamente, no hay un mozo para cada mesa, proveer un iPad a cada mozo, equivale a una inversión aproximada de $12 millones de pesos o US$ 26.000, aproximadamente. Considerando que el mozo transporta el iPad, no se requieren más "costos" de implementación.

Si consideramos la segunda opción, la inversión es un 72% menos que la primera opción.

Entonces, la pregunta obvia es ¿Porqué no se le entregó un iPad a cada mozo en vez de habilitar uno en cada mesa? Yo quiero pensar que hay alguna otra razón por la cual se eligió el primer escenario de inversión respecto al segundo porque, económicamente hablando, no tienen comparación.

Tecnología por Tecnología
Mi experiencia como cliente fue que la solución no se usó nunca. Puede ser que esté destinado a horarios peak y/o a momentos en los cuales no hay tantos mozos disponibles, sin embargo, hecha la inversión, no hay una razón de peso para no hacer uso de la tecnología de manera permanente.

Esto es similar a lo que sucedió, hace algunos años atrás, con los cobradores automáticos de las micros amarillas. La solución era tan ineficiente que, rápidamente, se buscaron mecanismos alternativos de cobro, llegando incluso a implementar los recordados "cobradores-humanos". En este caso, la tecnología sólo sirvió para hacer millonario al que vendía las máquinas y no para resolver el problema.

Ahora bien, si el sistema se usa y permite, efectivamente, agilizar los pedidos desde las mesas sin la asistencia de lo mozos, la pregunta inmediata es si la cocina está preparada para atender todos los requerimientos de manera correcta, esto es, según el orden del pedido, tiempo de los platos, etc. Si la cocina no está preparada y/o no tiene los mecanismos para administrar ese flujo constante de pedidos, entonces, como comenté en mi post anterior, la solución se implementó a medias.

Por lo pronto, tendré que ir nuevamente al restaurant para ver si puedo usar el sistema y vivir la experiencia virtual de atención.

martes, 14 de mayo de 2013

La Solución a Medias

Hace algunos días tuve un "siniestro" (como se denomina en la industria de las aseguradoras un robo o hurto). Para los que no han pasado por una situación así, el proceso es relativamente, engorroso:
  1. Sobreponerse al "siniestro", es decir, acordarse de la mamá de todo el mundo y, después de un rato, calmarse. 
  2. Ir a la comisaría más cercana.
  3. Hacer la denuncia lo que implica, en términos simples, tratar de responder a preguntas imposibles (¿Hay testigos? ¿Tiene algún sospechoso?) y, luego, verificar que los "hechos" han quedado correctamente descritos en español del siglo pasado.
  4. Recibir un comprobante de la denuncia con el número de la Fiscalía correspondiente.
  5. Llamar al día siguiente al número indicado y solicitar el "número de parte". 
  6. Registrar el número de parte en el comprobante para no olvidarlo. 
Hasta ahí el proceso es relativamente estándar. Dependiendo de la compañía de seguros con la que se tenga contratado el seguro, el procedimiento siguiente comprende el ingreso de los datos del siniestro vía web y/o una llamada al call-center para informar los antecedentes. El objetivo final de esto es recibir la autorización para llevar el auto a algún taller para su reparación.

En esta oportunidad me tocó realizar el ingreso de los datos vía web. Una vez terminado el trámite, recibí una confirmación de que el proceso había concluído y que recibiría, posteriormente, las instrucciones de cómo seguir por mail.

Pasaron unos días y recibí un mail de la compañía que indicaba que había algún antecedente que no estaba bien informado. Como lo que faltaba era relativamente simple, instintivamente, respondí el mail inmediatamente con la información pendiente.

Pasaron algunos días y no había recibido ninguna noticia de la compañía de seguros. Tenía el recuerdo que la vez anterior (efectivamente me ha pasado más de una vez), había sido mucho más rápida la respuesta, razón por la cual, revisé el correo enviado previamente sólo para asegurarme que no se me hubiera escapado algún detalle.

Al leer el correo de nuevo encontré el error. Al final, había una frase que decía:
"Por favor, agradecemos No Contestar a esta casilla"
Eso explicaba la demora. No había que responder "por correo", el correo que indicaba que faltaba información. En el mail venían indicados los teléfonos a los que había que llamar para continuar el proceso.

En términos simples, el proceso estaba cojo. Se solicita el ingreso por mecanismos virtuales de la información, sin embargo, no se completa el proceso de la misma manera. Es cierto que hay excepciones pero ésta, claramente, no lo era. Es similar a tener que ir a pagar físicamente a la tienda, después de haber realizado la elección y la compra de algun producto vía web.

En el contexto de la experiencia de usuario y de la transición (lenta pero segura) del modelo de atención de clientes a mecanismos 100% virtuales, es necesario y fundamental, asegurarse de que los trámites/procesos que se vayan a habilitar de manera virtual, efectivamente, se puedan realizar completamente de manera virtual.

Cualquier otro escenario será, símplemente, una ilusión que es necesario evitar ya que, a la larga, los clientes se darán cuenta.

(Fuente: Twitter)

viernes, 10 de mayo de 2013

El Dilema de las Porciones y el Desarrollo

Considere los siguientes avisos:


¿Cuál de las promociones conviene más?

Obviamente la a), pero... ¿Siempre se cumple esto?

El otro día fui al cine con mi familia a ver Los Croods. Nada espectacular la película, sin embargo, mis hijas se morían de ganas de verla. Como es habitual, antes de entrar a ver la película, compramos algo para comer. Me acerqué al mostrador y le pedí a la cajera lo siguiente:

 
En respuesta a mi pedido, la cajera me ofreció lo siguiente:

¿Cuál de las promociones conviene más?
 
Por precio, obviamente, la segunda promoción es la mejor, sin embargo, en términos alimenticios, no tienen relación. Veamos las calorías de cada una de las ofertas anteriores.
 
Promoción 1 = 500 calorías
Promoción 2 = 3.000 calorías
 
Considerando lo anterior... ¿Ahora cuál de las promociones conviene más?

Chile es un país en el que la tasa de obesidad es cada vez más alta. Según los estudios, el 33% de la población entre 20 y 30 años tiene obesidad. Se han realizado diversos programas para intentar frenar esto enseñándole a la gente a comer sano, esto es, comer frutas y verduras de manera habitual en reemplazo de la comida chatarra o rápida. McDonalds, incluso, ha incorporado en sus menús de la Cajita Feliz (que la siguen vendiendo con los juguetes aún cuando se supone estaba prohibido) un postre de manzana en trozos. Algo así como 1/4 de manzana en pedacitos y la posibilidad de reemplazar la bebida por un jugo de naranja "natural".

Más allá de estos esfuerzos, mi impresión es que el problema no es sólo lo que la gente come, sino que, cuánto come. Cuando una persona piensa en comer galletas, no se come una o dos, se come el paquete entero. Si se pide una pizza a domicilio, en términos proporcionales, sale infinitamente más conveniente pedir una promoción con pizza XL que una promoción con pizzas más pequeñas. Situación idéntica a la que ocurre en el cine. La oferta es demasiada y, el problema, es que la gente se acostumbra a comer demasiado o, dicho de otra manera, a no comer lo justo.

Según los estudios realizados en Estados Unidos, las porciones han aumentado en un 69% en el último milenio. El objetivo principal, además de comer variado, es que las personas aprendan a comer la cantidad justa (ver Lifesize). A diferencia de nuestros antepasados, el desarrollo y el progreso nos permiten tener al alcance de la mano, casi de manera permanente, alimentos en cantidades superiores a lo que realmente necesitamos. Esto no sólo es un problema desde el punto de vista de la obesidad, si no que lo es también desde el punto de vista del uso racional de los recursos.

Adicionalmente, si consideramos la carga genética que nos hace fanáticos del azúcar y las grasas, la situación es peor. Un pobre Brócoli, Tomate o Lechuga (7 calorías) tiene la batalla perdida contra un Pollo Frito (560 calorías), una trozo de Torta de Milhojas (380 calorías) o un Sundae con Salsa de Manjar (315 calorías). La opción es evidente (vinculada al placer). Si a esto le sumamos los precios y las promociones, la situación es peor: Una Hamburguesa con Queso, lista para comer, cuesta $500 pesos. Un Pimiento Verde cuesta $400, un pimiento rojo cuesta $800. Una lechuga cuesta $600.

Considerando la interminable oferta y el acceso permanente a alimentos existente, las estrategias de alimentación orientadas a comer sano están destinada al fracaso a menos que se aborde, en paralelo, la concientización respecto al tamaño adecuado de las porciones y lo que es recomendable para evitar el "desequilibrio positivo" (acumulación de calorías) como resultado de consumir más calorías de las que se gastan.

Para las personas con obesidad, la dieta y el ejercicio es el único camino para intentar reducir si IMC. La "dieta" siempre se asocia con restricciones y cambios de hábitos en la alimentación que, casi siempre, resultan imposibles de cumplir: desayunar liviano, almorzar ensalada todos los días, etc. Considerando esto, una estrategia alternativa es reducir el tamaño de las porciones. Si se va a comer pizza, no pedir la XL. Si se va a tomar bebida, un vaso normal (y light). Si se va a tomar once, una marraqueta únicamente, etc. Mi estrategia personal (y que me ha dado resultado) es simple: privilegiar las proteínas y dejar la mitad de la porción que me sirven. De esta manera, en términos simples, como menos y sin restricciones y, aún cuando he intentado en múltiples oportunidades que me sirvan menos en los restaurantes, no hay caso, las porciones son grandes.

El objetivo principal es que la alimentación cumpla su objetivo y no se convierta en una batalla... como en el programa Man vs Food, en que el protagonista, Adam Richman, recorre diversos lugares para comer e intenta romper los records más absurdos del planeta.