Sería el año 2003 o 2004 cuando se celebró aquella reunión. En aquella época los servicios web, los de verdad, los de SOAP y WSDL, eran el no va más y yo todavía me creía lo que me contaban en las conferencias. Por tanto es normal que cuando alguien propuso utilizar ficheros para comunicar dos sistemas, yo le mirase con cara de “madre mía, de qué siglo has salido tú” y le explicara el atraso que eso suponía. Que lo que realmente necesitábamos para ese escenario eran servicios web, claro.
Al final el sistema se implementó con servicios web, funcionó y, de hecho, todavía sigue en producción y sin visos de ser reemplazado. Seguramente también habría funcionado dejando ficheros en carpetas, aunque la verdad es que eso no importa mucho ahora.
Hoy en día, los servicios web ya no están de moda, o al menos no los de SOAP y WSDL, pero a cambio la definición se ha relajado y abarca casi cualquier cosa con la que se pueda interactuar a través de HTTP. Hay APIs basadas en xml (aunque no SOAP), APIs más o menos RESTful, APIs estilo RPC… en fin, APIs para todos los gustos. A la hora integrar aplicaciones, siguen pareciendo la opción Buena™, a menos que necesites algo más exótico como una cola de mensajes o un bus, pero el 90% de las veces los puntos de integración que ofrecen los sistemas son APIs web.
Por eso tiene cierta gracia que, justamente ahora que los herederos de los servicios web que yo defendía hace tantos años dominan el mundo, me vea en la posición de mi interlocutor de aquella reunión y mi propuesta para integrar (ciertas) aplicaciones sea mediante ficheros de texto.
Porque sí, de eso va este post. De explicar por qué, en este mundo moderno y ultraconectado de APIs web, todavía hay escenarios en los que utilizar unos simples ficheros de texto para integrar aplicaciones puede ser una buena opción.
Empezamos.
Simplicidad al poder
En los más de diez años que han pasado entre aquella reunión y hoy, he cubierto mi cupo de integraciones con multitud de mecanismos diferentes. Toda la gama de APIs web, sockets con protocolos binarios, remoting, colas de mensajes, dlls, controles ActiveX, conexión serie, bases de datos…
¿Por qué entonces volver a utilizar ficheros de texto, como si esto fuese 1990?
La mayoría de las ventajas de utilizar ficheros de texto se derivan de lo extremadamente simple que es la solución.
Leer y escribir ficheros es algo fácil de realizar en prácticamente todos los lenguajes de programación, y si eliges un formato razonable (me da igual XML, JSON, YAML, CSV o lo que sea), no suele ser complicado encontrar librerías para tratarlos de una forma cómoda.
Al aislar el API de la capa de transporte, tienes mucha flexibilidad para trasportar esos ficheros. Desde una carpeta compartida en una red local, una conexión (s)ftp/scp o una carpeta sincronizada con DropBox, hasta un pendrive USB que puedas llevarte en el bolsillo (y, ojo, no subestimes el poder del pendrive que te puede salvar más de una vez). De hecho, siempre puedes implementar a posteriori una fachada sobre el sistema de integración que use HTTP de cara al exterior, pero genere ficheros hacia tu aplicación.
Utilizar algo tan básico como ficheros de texto hace que puedas aprovechar un montón de herramientas genéricas que ya dominas.
Puedes visualizarlos y modificarlos con tu editor de texto favorito. Es trivial hacer copias de ellos para ejecutar otra vez la integración en un entorno de depuración. También es fácil comparar el contenido después de distintas ejecuciones. Son estupendos para utilizar como salidas en tests de aprobación.
Todo esto se puede hacer con otros sistemas de integración, y actualmente existen herramientas como Fiddler o Postman muy potentes para ayudarnos a hacer cosas similares con APIs web, pero no dejan de ser más herramientas a manejar. Posiblemente a ti o a mi nos dé igual porque ya estamos acostumbrados a usarlas, pero créeme, para un usuario (y para ciertos “profesionales” de la informática) es mucho más sencillo copiarte los ficheros de una carpeta que capturarte una sesión con Fiddler.
Poder monitorizar el comportamiento de una integración basada en ficheros de texto es muy sencillo y nada intrusivo, incluso en producción. Basta con mirar lo que hay en una carpeta. Utilizando un poco de sentido común y un par de convenciones apropiadas, como mover/renombrar los ficheros procesados en función de si el proceso ha sido correcto o no, saber si el sistema está funcionando o hay errores es muy fácil. Poder automatizar “alertas” sobre eso, a partir de una tarea programada que haga un “dir *.error” y mande un email no cuesta nada. Claro que no tienes la sofisticación de un sistema de monitorización “de verdad”, pero es que, al igual que pasa con los logs, a veces no necesitas tanta complejidad.
Si la aplicación esta caída, el propio sistema de archivos actuará de almacenamiento intermedio, permitiendo que la información se siga recogiendo hasta que la aplicación vuelva a estar activa y pueda procesarlos. Incluso es factible copiar fácilmente todos los archivos a otra máquina y procesarlos en ella.
Si quieres alterar los datos de entrada para hacer pruebas, o incluso para corregir errores, sólo necesitas modificar los ficheros. Si un sistema recibe como entrada ficheros de texto y fallan porque algo está mal, podemos editarlos y volver a procesarlos, evitando perder la información. Hacer eso a través de un API web implica una coordinación mucho mayor con el cliente, o haber hecho un desarrollo específico para ello.
Algo similar ocurre si necesitamos “adaptar” los datos a la entrada o salida del sistema. En el caso de los ficheros de texto, meter entre los sistemas integrados un script o aplicación que haga una transformación mientras los mueve de carpeta es mucho más sencillo que meter un proxy delante de un API web para transformar las peticiones o las respuestas.
Hay ocasiones en que necesitamos interactuar con el sistema que genera la información, por ejemplo para forzar esa generación o para pasar algún tipo de parámetro. Para conseguirlo podemos ofrecer una aplicación de consola que interactúe con nuestro sistema. Esto, que puede sonar raro, es lo mismo que se hace en sistemas *nix: utilizar aplicaciones de línea de comandos relativamente simples que puedan llamarse unas a otras. Es una opción razonable y muchas veces resulta sencillo de utilizar para nuestros clientes.
Llegamos hasta donde llegamos
Este tipo de integración se adapta mejor a unos escenarios que otros y hay que ser consciente de ello.
Funciona muy bien cuando la comunicación entre los sistemas a integrar no requiere demasiada interacción y usa un “API” poco granular (coarse grained, que dirían por ahí), idealmente basada en datos más que en operaciones. El escenario prefecto es la típica importación de datos en modo batch entre sistemas.
Es posible serializar eventos/mensajes/comandos a ficheros y simular algo parecido a un bus o una cola de mensajes, con operaciones de tipo fire and forget, pero si estás en este caso, el sistema de ficheros empieza a quedarse corto y deberías considerar alternativas más apropiadas.
Incluso he visto (y padecido) sistemas de integración basados en ficheros que trataban de emular un protocolo request/response síncrono. Definitivamente, si tu integración requiere algo así, los ficheros de texto son una opción pésima.
Independientemente de lo bien o mal que se ajuste a tu escenario de integración, hay ciertas características del sistema de ficheros que imponen unas limitaciones que pueden ser importantes.
Suele ser complicado implementar bien el control de concurrencia. Al final vamos a tener dos o más procesos pegándose por acceder a los mismos archivos, y es necesario coordinarlos para evitar que se pisen, se lean ficheros incompletos o se borren antes de tiempo. No es imposible hacerlo bien, pero si se hace sin cuidado puede dar lugar a problemas difíciles de detectar y depurar (y ya sabéis que por desgracia tener cuidado al desarrollar suele ser la excepción más que la norma).
Unido a esto, no hay muchos sistemas de archivos transaccionales (y cuando lo son no se suelen aprovechar), por lo que no podemos garantizar la atomicidad de las operaciones y debemos estar preparados para que una ejecución del tipo “leer, procesar, renombrar” pueda verse interrumpida a medias, dejando el sistema de ficheros en un estado inconsistente. En el fondo es probable que estemos realizando implícitamente una transacción distribuida entre el sistema de archivos y la base de datos, y es imposible garantizar la integridad de la operación completa.
Para lidiar con ello es recomendable que el proceso de integración de cada fichero sea idempotente. Así, en caso de duda, si encontramos una operación a medio hacer, podemos repetirla desde el principio sin miedo. Esto no siempre es posible o fácil, y si tu aplicación no encaja con ello, tal vez te merezca la pena usar otros mecanismos de integración o correrás el riesgo de perder/duplicar información, lo que suele ser poco deseable (aunque también existen escenarios en los que es perfectamente admisible).
Otro punto importante es el rendimiento y la escalabilidad. Por muchas mejoras que se hayan introducido con el uso de SSDs y las cachés de los sistemas operativos, estamos tocando disco todo el tiempo y eso no es precisamente rápido. Si necesitas comunicar con 400 clientes cada 10 segundos, utilizar el sistema de archivos es una pésima idea. Por otra parte, si esos 400 clientes van a enviar información un par de veces al día y puedes procesarla con una tarea programada, utilizar un sistema de buzones basados en carpetas es una solución perfectamente válida.
Conclusiones
A veces cuando planteo una solución de integración basada en ficheros me miran con cara rara, como si fuese un ermitaño que no hubiese oído hablar de APIs REST o un vago que no quiere implementarlas y quiere ir a lo fácil.
En realidad, cuando elijo este tipo de soluciones es porque creo que las ventajas de usabilidad son importantes para el escenario que estoy tratando. De hecho, como hemos visto en este post, implementar correctamente un sistema de integración basado en ficheros tiene más dificultad de lo que aparenta para gestionar correctamente la concurrencia y la (falta de) transaccionalidad, por lo que probablemente muchas veces sea más sencillo a nivel de desarrollo implementar un API Web simple.
Sin embargo, ese esfuerzo extra a la hora de implementarlo redunda en unos menores costes operacionales de despliegue, mantenimiento, monitorización y uso, por lo que puede merecer (y mucho) la pena.
También es importante tener en cuenta el perfil de los usuarios potenciales de tu sistema de integración.
No es lo mismo diseñar un sistema de integración para gente con conocimientos limitados de informática “clásica” que diseñarlo para ser usado por los hipster de Javascript. Todavía hay mucha gente que se apaña bien para hacer una aplicacioncilla que lea y escriba ficheros en Visual Basic, pero empezar a hablar de peticiones HTTP y cabeceras de autenticación les resulta complicado.
Tampoco es lo mismo desplegar y monitorizar el sistema para el equipo de TI de una gran empresa con infinidad de sistemas de control centralizados, que para el administrativo de una PYME que bastante tiene con llegar a una carpeta y ver si hay archivos dentro o no.
Como siempre que se valoran temas de usabilidad, hace falta pensar en los futuros usuarios y no existen verdades absolutas.
En definitiva, huir del “másmolismo” (gracias Javi por la palabra) es importante. Que algo este de moda o demodé no debería ser nunca el factor técnico fundamental a la hora de decidir utilizarlo o no. Es mejor dejar los prejuicios a un lado y analizar las cosas como lo que son.
No hay posts relacionados.