Diseñando una arquitectura (I/IV): Estudio de la Situación Actual

Hace aproximadamente año y medio me embarqué en lo que está siendo ha sido mi experiencia profesional más compleja, importante e interesante: mejorar la forma de desarrollar aplicaciones web de una organización. Es un buen momento para mirar atrás.

Lo haré en cuatro entradas:
I: estudio de la situación actual (actual por aquél entonces, claro).
II: selección de las alternativas de solución.
III: implantación de la solución.
IV: conclusiones.

0. Antecedentes

En los últimos años había estado trabajando con tecnologías J2EE, tanto profesionalmente como "en casa", para proyectos propios. Anteriormente había hecho alguna cosa en PHP, y me gustaba mantenerme al día de las novedades de la industria (RoR, Phyton...), aunque no le pudiese dedicar tiempo en profundidad. En general, todo para, en mayor o menor medida, aplicaciones de gestión de datos (quien esté buscando sistemas de tiempo real o simuladores aeroespaciales me temo que tiene que cancelar su suscripción a este sitio).
De esta experiencia formé una serie de axiomas que suelo tomar como ciertos (aunque al estudiar informática la conclusión que te queda es que la única respuesta que siempre es válida es 'depende'):
  • La separación entre capas es una Cosa Buena:
    • Debe haber una capa de acceso a datos "tonta", que no tome decisiones y que símplemente sirva para acceder a bases de datos. Debe tener esencialmente 4 métodos (buscar, insertar, actualizar y borrar), salvo añadidos por eficiencia.
    • La capa de lógica de negocio, por encima de la de datos y por debajo de la de presentación, es en la que se programa todo lo que aparece en las especificaciones, desde el flujo de la aplicación al control de datos ("quién puede ver/editar qué en cada momento").
    • Las dependencias van hacia abajo, los datos hacia arriba.
  • No te repitas (DRY).
    • Corolario: no cortapegues (mejor: ¡¡NO CORTAPEGUES!!).
  • Para aplicaciones pequeñas, PHP o RoR o similar, para aplicaciones grandes, J2EE.
    • Por favor, no empecemos un flamewar aquí. Ya sé que Flickr, por ejemplo, es PHP y un montón de ejemplos más. Sin embargo, intenta hacer consumir a algo que no sea Java o .Net unos cuantos servicios web de terceros y verás lo "estándar" que son. Sí, con PHP puedes hacer OO y otro buen montón de buenas prácticas, pero si ya es difícil mantener el código bajo control con Java, no quiero ni pensar lo que ocurre con otros. Por no hablar de las herramientas, claro... Fin del tema :). Para discutir sobre esto, otro día :).
  • Hacer páginas con etiquetas es bueno (claridad, uso de librerías de componentes...), meter código Java en las JSPs es malo: inmantenibilidad, dificultad para trazar errores...
  • Ajax es bueno, hecho con Javascript a mano puede no estar mal, pero si tienes una librería que te lo proporcione es mucho mejor.
    • Esto tiene un corolario: ajaxificar los datos (posiblemente) es más eficiente, ajaxificar el interfaz es (posiblemente) más productivo. Escribir Javascript a mano (o con con Dojo, por ejemplo) suele llevar a hacer solicitudes Ajax que devuelvan datos. Esto consume menos recursos. Sin embargo, usar librerías de servidor (Ajax4JSF, ICEFaces...) suele llevar a que lo que se solicita son "trozos del interfaz". Esto no es siempre cierto (GWT, por ejemplo, es una excepción) pero era lo más habitual por aquel entonces.
I. Estudio de la situación actual

Corrían finales de 2006. Struts (Action, 1) comenzaba a ser considerado demodé, y Ajax era lo que tenías que decir en una entrevista si querías atraer la atención. JSF seguía con su mala salud de hierro, como ahora. Una miríada de frameworks web (Spring Web, Wicket, Web Works, Tapestry...) esperaban que comenzase a morir de verdad para regodearse sus despojos. Microsoft, tras la guerra con Sun, había publicado .NET, y la pregunta entre todos los encorbatados era ¿J2EE o .NET?. Dojo era la librería Javascript por excelencia, con sus estándares de no documentar (y si documentas, hazlo mal, sin actualizar y sin completar). Si querías mantener una conversación geek tenías que saber que lo cool era Ruby On Rails, que Google había roto todas las convenciones con GWT.

Al llegar a la nueva organización me encontré con una situación... poco habitual. Mientras el resto del mundo se empeñaba en optimizar la productividad y mejorar la calidad del desarrollo mediante librerías Java, o diréctamente renegaban del mundo J2EE para salir a otras alternativas, allí se seguía desarrollando como hablaban los manuales de 5 años atrás: servlets y JSPs (¡o sólo JSPs!). Estamos hablando de un entorno con grandísimas restricciones y los responsables de la arquitectura de las aplicaciones estaban en gran medida con las manos atadas. La superorganización (la casa matriz, la "nave nodriza", aquellos de quien dependíamos) imponía su ley (muchos, en mi modesta opinión, debidos al síndrome NIH), con sus problemas:
  • Desarrollo con una versión bastante antigua de un IDE:
    • El cliente CVS era muy malo y problemático. Eso no era un problema para la superorganización porque ellos no usaban ningún repositorio de código para trabajo compartido (así hasta el 2008, increible pero cierto), pero sí para nosotros, y eso nos hacía tener que usar un cliente externo.
    • Desarrollábamos sobre el OC4J integrado, que no era el de producción.
  • Servidor propietario, por lo que al no ser libre apenas hay documentación ni soporte sobre él.
  • Uso de framework propio:
    • Clases que generan código html (había que hacer cosas como new DropDown() en las jsps).
    • Diseño en una capa (todo en JSPs), llegando al extremo de programar SQL en las JSPs.
      • Aquí hay que decir que en la organización se hizo un diseño MVC que simulaba la estructura de Struts, de forma que nuestras aplicaciones sí seguían dicho patrón (aunque las de la superorganización no).
    • Wrappers para clases existentes (un envoltorio, por ejemplo, para Connection, que impide obtener el objeto propiamente dicho. En resumen, envoltorios limitados de clases existentes.
    • No disponíamos del código fuente.
    • Documentación sin actualizar.
    • Ninguna librería "estándar": ni siquiera Log4J, así que ni hablar de cosas como Hibernate, Struts, Commons-X...
    • Dependencia (oculta, sin documentar), de variables de sesión.
    • Las aplicaciones sólo funcionaban en Internet Explorer.
Estas restricciones habían llevado a otras malas prácticas adicionales:
  • Se repetía muchísimo código, por una mezcla de los problemas y restricciones impuestos y descuido propio. Ejemplos:
    • Las clases de acceso a datos tenían tantos métodos de consulta como páginas, así que la separación entre capas era pobre.
    • Cortapega entre páginas en vez de inclusión.
    • Cortapega entre clases en vez de agregación o herencia.
  • Muchas validaciones de datos de usuario (sólo) en Javascript.
Como podéis imaginar, la situación actual chocaba frontalmente con mi visión del desarrollo de aplicaciones web (y de la informática en general). Conviví con todo esto en el desarrollo de una aplicación, en papel de analista. Es cierto que las cosas iban saliendo así, pero no creo que esta fuese la mejor forma de hacerlo:
  • Se genera código de mala calidad, inmantenible. Seguramente este problema habría sido mucho mayor de no ser porque la naturaleza de muchas aplicaciones desarrolladas era casi de usar y tirar, con un ciclo de vida muy corto (uno o dos años de vigencia). Sin embargo, por ejemplo, la aplicación con la que comencé ya está sufriendo estos problemas. Comenzó con el objetivo de ser una aplicación pequeña y simple y desarrollada rápidamente, y las mejoras que se le están metiendo están provocando problemas que no tendríamos con otro tipo de desarrollo.
  • Todo se hace a medida para cada ocasión (lo más sangrante es escribir una SQL para cada situación, un simple cambio de nombre de una columna podía llegar a ser un cambio dramático).
Tras esta primera aplicación se me dio la oportunidad de hacer una propuesta de un diseño nuevo, una nueva arquitectura para nuestras aplicaciones partiendo de cero, una nueva forma de trabajar. Este será el contenido de los siguientes posts. Como anticipo del último, puedo decir que estoy satisfecho con las decisiones tomadas, pero no del todo con los resultados, así que hay que recapitular en qué cosas hemos hecho mal. Podéis también ir imaginando el contenido del post siguiente al último ;).

Posted by Juan Ignacio Sánchez Lara 10:15  

3 Comments:

  1. Blaxter said...
    Para aplicaciones pequeñas, PHP o RoR o similar, para aplicaciones grandes, J2EE.

    Para cada aplicación, la mejor opción. Para una aplicación grande dudo que la mejor opción sea todo en un mismo lenguaje.

    Lo peor, en mi opinión, es intentar casarte con una tecnología en concreto. Salvo que no tengas gente capacitada para aprender cosas nuevas, que entonces ya apaga y vámonos.
    Nacho said...
    @blaxter, sé que tienes razón en que para cada caso la solución óptima es elegir la tecnología óptima. Sin embargo, cuando organizas a un grupo de desarrollo no demasiado grande, ni demasiado flexible, ni con demasiada experiencia o iniciativa, etc., conviene atarse algo más. Si la mayor parte del grupo (¡y los jefes!) tuviese la madurez suficiente, se podría ser más flexible.
    Lo habitual (al menos con lo que me he encontrado) es que la experiencia es algo justa/insuficiente, que la madurez de la organización es justa/insuficiente... Ceñirse a una buena solución permite formar y mejorar, a la vez que generas un producto suficientemente bueno.

    La ingeniería del software tiene poco de ingeniería tradicional, pero sí una cosa. Por ejemplo, cuando se construye un puente no se ajusta al máximo con los materiales, ni con la planificación, ni con la logística. La mejor solución no tiene porqué ser la solución óptima.

    IMHO, por supuesto ;)

    ¡Gracias por el comentario!
    Ataulfo said...
    Soy un estudiante de informática que pasaba por aquí y he visto que este artículo tenía buena pinta (más o menos como el resto del Blog :D). ¡Espero con ganas el resto de los artículos de esta serie!

Post a Comment