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.
Mmm… primero comentar que hay bastantes protocolos que no fijan un canal de transmisión predeterminado y que en cada despliegue se usan indistintamente servicios web, colas, smtp, ftp, etc… es decir, si bien hay protocolos que definen el contrato sobre un canal de transmisión concreto (ej. el WSDL) el recíproco no siempre es cierto. No es lo más frecuente (lo que más se ve «por ahí»), pero siempre han sido comunes (al menos para mí) los protocolos sin canal. Dichos protocolos siempre han tenido como soporte mensajes/registros que de cara al canal son isomorfos a un fichero (ej. los típicos ejemplos XML). Así, yo no lo vería como una vuelta a los 90, porque nunca he dejado de verlo.
En cuanto a usar el sistema de archivos sí lo veo de vez en cuando (sobre todo sobre FTP), pero yo lo desaconsejo totalmente, porque existe nula gestión del control de la recepción (ej. para FTP o similar habría que pactar enviar el md5, zip+crc, … para verificar integridad). Es decir, como canal, da un pobre soporte; si el protocolo ya gestiona esas contingencias pues podría no ser un problema, pero normalmente el protocolo ya supone un control previo de la transmisión (por el canal que sea).
No obstante, para uso interno (ej. replicar copias de seguridad, distribuir scripts, archivos de configuración, …) entiendo que es muy común (yo lo hago habitualmente) usar simples archivos directamente sobre el sistema de archivos.
Obviamente, todo depende del contexto.
umm… tendría buscar en alguna galaxia muy, pero muy lejana :D para encontrar momentos en los que no he estado del todo de acuerdo con lo que escribes… pero hoy, ummm :)
Yo creo que el enfoque al problema es lo que te da pie a argumentar el post y desde ese enfoque, tienes razón. El problema es que el mundo actual, cambia mucho más rápido que la usabilidad, el mantenimiento o la monitorización.
Creo que (opinión), la transición de aplicaciones monolíticas a arquitectura de micro-servicios (APIs) está muy lejos de ser una moda o ¿¿másmolismo?? :D y ha llegado más por una necesidad de negocio. Esto no es TDD, DDD o el último ORM…
Muy pocas aplicaciones que salen al mercado, triunfan por su conjunto, por todo lo que hacen. Siempre hay algo muy específico que llama la atención de los grandes. Ejemplo: en una aplicación que procesa datos en segundo plano, puede que sea más práctico por todo lo que mencionas, que esos datos se transmitan en archivos. Al pasar el tiempo, descubres que tu algoritmo de procesamiento es lo mejor del mundo mundial y es donde realmente destacas. ¿Cuentas con un modelo capaz de sacarle dinero solo a esa parte de tu aplicación? Transmitiendo por archivos, no es imposible pero sí complicado. Antes llegará un grande y enterrará tu empresa solo para quedarse con tu super-process… :)
Conclusión: no creo que hoy en día, por muy pequeño que sea el modelo de negocio, se me ocurriría no intentar llevar la solución a una arquitectura de micro-servicios. Total, una aplicación pequeña no es más que una gran aplicación que acaba de nacer ¿no? :)
Está bien discrepar, Omar :-)
Sobre la parte que comentas de los microservicios, yo sí creo que es una moda (ya veremos cómo de pasajera) y no creo que cualquier aplicación se beneficie de ese enfoque, pero bueno, el tiempo dirá. Algún día debería escribir un post con mi opinión para poder discutirlo tranquilamente.
En cuanto al ejemplo que pones de capitalizar una parte del sistema, normalmente el valor no va a estar en el API como tal, sino en lo que hace ese API (ya sean los datos que ofrece o los algoritmos que encapsula), y ya puestos a «pivotar» como dicen los modernos, cambiar la capa de transporte de ficheros a un API Rest (u otra cosa) no debería ser muy complicado. De todas formas, nunca me he visto en esa tesitura, por lo que posiblemente esté equivocado.
:D Estaré atento a ese post…
A ver, está claro que lo que realmente aporta es la lógica de negocio y no el transporte, pero en una arquitectura de micro-servicios me suena a poco pensar solo en el transporte.
En tu caso, al tener los procesos separados, seguramente será más fácil adaptar y aún así me cuesta verlo. Recuerda que expones tu funcionalidad como servicio y que a partir de ese momento, será otro modelo de negocio totalmente independiente…
va, va.. mejor espero el post :)
Hola Juanma,
Pues fíjate que ahora mismo la integración de datos mediante ficheros es una de las partes más importantes (y ahora mismo problemáticas) del sistema que tenemos ahora mismo entre manos. Y sí… en el hipsteriano siglo XXI.
Eso sí «Es mejor dejar los prejuicios a un lado y analizar las cosas como lo que son». Ya veremos qué tratamiento le damos más adelante, si es que le damos alguno :-)
Gran post, como siempre!!
Un saludete!
Un problemita extra que le encuentro al tema de integrar mediante archivos es que, bajo ciertas condiciones, la codificación de los archivos puede dar grandes dolores de cabeza.
Sobre todo cuando algunos datos de los que se guardan son tipados por los usuarios … ultimamente me han tocado varios proyectos donde hay que utilizar archivos para integrar entre sistemas y he visto cosas que nunca hubiera imaginado pudieran suceder!!! jejejeje
Más allá de eso, concuerdo con lo que dice el post, bajo ciertas condiciones es la alternativa más eficiente.
He leído el post y no me he podido resistir… lo primero, felicidades porque creo que está todo muy bien explicado y expuesto.
Como desarrollador e integrador de sistemas desde hace algo más de 25 años he visto, como podréis imaginar, de todo, DE TODO ;-) No me ha gustado lo que has puesto de que hay que hacerlo para ciertos «profesionales» de la informática y que termines diciendo que es lo que tú haces/prefieres en muchos casos…
No me gustan las etiquetas… pero en general me parece muy acertado el enfoque de que en cada caso hay una solución ideal dependiendo de quién lo tenga que usar y cuáles sean las circunstancias de cada proyecto.
Yo no creo que los servicios web, las API Rest y similares sean una moda, creo que están para quedarse, pero tampoco descarto o enterraría la opción de la transmisión de archivos porque es lo que en muchos casos se utiliza y también está para quedarse… simplemente no hay que ser dogmático y ser abierto a diferentes realidades o circunstancias…
Lo dicho, me ha gustado el post!
Saludos