Abuso de recursos en aplicaciones web y otros horrores
Les dejo esta anécdota a los programadores que visitan javamexico.com en busca de respuestas para ciertos problemas básicos y que a veces se ofuscan buscando algo muy concreto y pierden de vista el diseño general de su aplicación. La moraleja: si tienes un problema que parece algo difícil de resolver y/o la solución es muy tediosa de implementar, lo más probable es que alguien ya lo haya hecho antes. Y probablemente hay algún proyecto de software libre que contiene ya la manera de solucionar tu problema de manera sencilla. El principio DRY: Don't Repeat Yourself (en contraste con el síndrome NIH, Not Invented Here, que es tan común en muchas casas consultoras donde prefieren inventar el hilo negro en cada proyecto en vez de utilizar soluciones externas).
Hace poco me tomé un proyecto que originalmente tenía otra persona y al revisar su código me encontré varios horrores... un pequeño sitio web que en cada JSP tenía código Java para abrir una conexión a la base de datos, pero desde encontrar el
y pedir
, hasta cerrarla en el
.
Podrán imaginarse que entonces ni siquiera usaban PreparedStatements; simplemente construían el SQL concatenando las partes del query, y por supuesto algunas de esas partes venían del URL o de un campo de texto de una forma. Por lo visto estas personas nunca habían escuchado acerca de la inyección de SQL. Esto fue de lo primero que cambié, antes de encontrarme con Bobby Tables.
Otra cosa que me encontré es que sí tenían unos DAOs, pero los instanciaban en cada JSP y les pasaban la conexión que habían abierto antes por medio del Driver. Así que cada que alguien visitaba una página, tendrían sus propios DAOs y su propia conexión a la base de datos. Aparentemente tampoco habían oído hablar de los singletons. Bueno y con tanto código Java en los JSP, se ve que tampoco estaban familiarizados con MVC...
Por otra parte tenían un bean que consiguieron no sé dónde para manejar las formas multiparte para permitir envíos de archivos. Este bean ya implementaba un método para devolver un singleton, de modo que ese sí lo usaban. El problema es que el bean tenía una lista de los archivos que recibía, por lo que con varios usuarios subiendo archivos, el bean guardaba todos esos archivos en memoria pero sin relacionar cada archivo con la página, thread, o usuario que los sube, de modo que en pruebas de concurrencia con dos usuarios ya era fácil hacer que cada usuario tuviera al final el archivo que había subido el otro usuario.
La solución? Pues primero que nada, meter Spring y DBCP y hacer algo de refactoring. Con DBCP implementé un pool de conexiones a la base de datos (que posteriormente puedo implementar directamente en el contenedor en producción), con Spring creo un DataSource que le paso a todos los DAOs, y controlo los DAOs para que se manejen como singletons. Con eso pude quitar todo el código de conexión a base de datos que estaba en los JSP. Luego, cambiar todos los queries y demás sentencias de SQL para ponerlas con PreparedStatements parametrizados y evitar así lo de la inyección de SQL. Con el commons-fileupload pude quitar ese bean raro que mezclaba los archivos que cada usuario subía y de hecho el código quedó más simple.
Ya después con algo más de refactoring, JSTL y algunos tags propios para la aplicación, pude quitar prácticamente todo el código Java de los JSPs, dejando solamente algunas expresiones de EL de JSTL. El sitio ahora soporta mucho más tráfico y utiliza menos memoria y recursos, porque tiene pocas conexiones a la base de datos, una instancia de cada DAO... aparte los cambios que después tuve que hacer (porque el sitio original estaba incompleto) fueron mucho más fáciles de aplicar porque ya estaba organizado lo que me habían entregado. La implementación de un par de servlets para encapsular cierta funcionalidad común a varias páginas también ha simplifcado las cosas.
Por el momento el sitio solamente usa JSP simples con JSTL, pero conforme se va complicando más porque el cliente ya lo vio funcionando y quiere más funcionalidad, creo que la opción será pasar a Tapestry para simplificar el crecimiento del proyecto. Migrar a Tapestry no será una pesadilla porque ya están las diferentes partes de la lógica repartidas de manera organizada y solamente habrá que reacomodar ese código, y al parecer incluso quitar mucho de lo que ya he hecho porque Tapestry maneja muchas cosas que actualmente estoy manejando por medio de tags y servlets.
Mmmmmm tal vez sería bueno tener una sub-sección en este sitio tipo TheDailyWTF.com para poner este tipo de anécdotas; seguramente varios de los que escriben en este sitio se han encontrado con historias de horror en proyectos donde han trabajado. Al final sirven de experiencia para que programadores más nuevos las lean y no cometan los mismos errores.
- ezamudio's blog
- Inicie sesión o regístrese para enviar comentarios
Al parecer es común
Al parecer es común encontrarse con este tipo de proyectos.
Hace algunos años pasé por algo similar, en el equipo de trabajo en el que estaba manejábamos Struts, con patrones de diseño Business-Delegate, Command, Value Object y DAO principalmente... en fin, todo muy ordenadito. De repente de otra área nos enviaron un módulo que había que corregir, tal como lo mencionas estaba hecho con puras JSP, donde dentro de ellas armaban su conexión y según ahí dentro hacían su DAO. Al poco tiempo nos hicimos amigos de los que desarrollaron ese módulo y durante un tiempo (quizá aún a estos días xD) no se la acababan con la carrilla por su "DAO", había bromas en las que les decíamos que casi casi querían sacar a su "DAO" a pasear con el usuario... xD o que deberían hacer que su DAO hiciera cosas como el clip de Office ya que lo ponían en la JSP para que el usuario interactuara con él xD.
Que bueno que menciones estos tips, son cosas esenciales hacer un buen MVC, hacer Singleton donde sea necesario, hacer que la consulta de datos sea óptima, y un extenso e importante etc...
--
Javier Benek
KISS
Existe otro principio que no se puede pasar por alto .... El principio del beso (KISS) el cual recomienda el desarrollo manteniendo las partes sencillas y comprensibles, el término es un acrónimo correspondiente a la frase en inglés Keep It Simple, Smart/Stupid Mantenlo simple, estúpido !!!
Creo que el síndrome NIH, Not Invented Here es como comentas uno de los más comúnes en las consultorías, vamos existen montones de librerías que ahi estan disponibles y a la vista pidiendo a gritos ser utilizadas y en lugar de ello muchas personas prefieren (por desconocimiento) reinventar la rueda.
Un ejemplo: Cómo hago esta o aquella operación con una fecha/hora de forma simple (principio KISS) ? Joda time
Me imagino que si la persona que hizo el sistema que comentas, en lugar de ello hubiera construido una casa le faltarían las traves, la instalación de luz ya se hubiera quemado, el mosaico levantado ... ya se le hubiera caido la loza en la cabeza a cualquiera de los individuos (yo creo que mi casa la construyó alguen así .. el techo parece el mapa del distrito federal :P) .... Y si hubiera construido un puente ? Dios santo !!!
En una ocasión me tocó hechar mano a un sistema realizado en Monterrey hecho con struts el cual estaba como dios manda, DAO's, en las páginas solo había tag libraries, la llamada a la lógica de negocio la separaban con interfaces y las implementaciones desde archivos de configuración los cuales eran llamados desde los controladores, estaba implementado el patrón de diseño Singleton, Factory, Method Factory, AbstractFactory, Command, Proxy, ServiceLocator, BusinessDelegate, Assemblers, DTO's ....
UN MOMENTO!!! ............ Singleton, Factory, Method Factory, AbstractFactory, Command, Proxy, ServiceLocator, BusinessDelegate, Assemblers, DTO's para llamar un método desde un controlador? SI, pero cómo le meto cosas nuevas a eso que construyó el super programador que se sabe de memoria todo el catálogo de patrones de diseño ? Una verdadera historia de terror mantener esto, aquí aprendí el concepto de antipatrones de diseño gracias al Programador Sr. que hizo este mounstrito.
En otra ocasión me encontre con algo que era todo lo contrario, las conexiones las hacían en las jsp's, no estaba organizado en dao's, dejaban conexiones abiertas :'(, muchisimo código java dentro de la página, no incluian una página genérica dentro de todas y se repetía código, pero lo mejor de todo ........ aquí viene mi carta fuerte, el número que estuve esperando durante toda la función .......... los nombres de variables no eran conexión o usuario, user o algo que te diera una idea con lo que estabas trabajando, en lugar de ello las variables tenían nombres como i1, a1, b3, b2, b4, b5, z3 (supongo le cambiaban letras para que fuera mas intuitivo :D), por un momento hasta llegue a pensar que el código estaba ofuscado pero NO !!! .... aquí yo no tuve la decencia ni el tiempo de repararlo, solo me aseguré que las conexiones cerraran correctamente, aprendí el lenguaje (a,b,c,d,e,f,g,h1,h2,h3) y a programar ... arbol que nace torcido, pero bien torcido, así se queda.
JavaRanch big moose saloon member
Antipatrones
Ah si, es muy común eso de abusar de los patrones y para demostrar que los conoces, implementarlos TODOS. Si fueran cocineros te servirían el platillo más condimentado del mundo, con curry, chile habanero, cardamomo, laurel, wasabe, chipotle, azafrán, vino tinto, vino blanco, marsala, mantequilla, azúcar, mostaza, mayonesa, aceite de oliva, aceite de coco, aceite de ajonjolí, aceite de aguacate, aceite de cacahuate, caldo de pollo, cebolla, ajo, echalot, sal de jamón, y todo salteado, asado, frito, horneado y pasado por nitrógeno líquido.
Alguna vez me forzaron a hacer una bestia así. Para un simple sitio pequeño, en .NET, porque MS había metido gente al proyecto y querían hacer un showcase de su tecnología pero usaron de ejemplo una aplicación web sencilla. Algo que había hecho en semana y media, y ya funcionaba, me tomó como 4 semanas modificarlo para que siguiera funcionando igualito pero ahora implementarlo .NET remoting binario sobre HTTP con autenticación remota, servicios separados en dos web servers, y una bola de patrones de diseño que luego ni al caso venían pero había que poner todos los que se pudieran. La base de código creció como al doble nada más para ponerle todas esas monerías. De plano decidí irme y luego el pobre cuate que lo heredó me llamaba para preguntarme por qué estaba todo tan enredado...
Given the choice of dancing pigs and security, users will choose dancing pigs, every single time. - Steve Riley