Hace unos años, si necesitaba añadir una funcionalidad nueva a Odoo, desarrollaba un módulo y metía allí todo lo necesario.
La interfaz, la lógica y la conexión con cualquier servicio externo vivían dentro del mismo entorno.
Después empecé a trabajar con Docker. Primero para resolver el problema de instalar nuestro Odoo 12 en una máquina nueva, que empezaba a ser una tortura. Había que instalar versiones antiguas de Python y dependencias que ya no compilaban fácilmente. Meter Odoo en su propio contenedor resolvía buena parte del problema.
Aproveché para llevar a contenedores el resto de servicios que necesita un Odoo estándar (PostgreSQL, principalmente) y los que requería nuestro negocio. Al final, tenía una composición de distintos contenedores que daban vida al sistema.
Esto me llevó, tiempo después, a ver que podía dejar de meter ciertas cosas dentro de Odoo.
El caso de Firebase
Para cierta aplicación de uso interno que desarrollé en Flutter y que corría en terminales Android necesitaba tener notificaciones push. Para eso utilicé Firebase Cloud Messaging.
El problema era que nuestro Odoo 12 vive en Python 3.8 y necesita determinadas versiones de sus dependencias. El SDK actual de Firebase necesita otras. Intentar instalarlo todo dentro del mismo entorno provocaba conflictos.
En lugar de pelearme con esto, abstraje el problema e hice un servicio independiente.
Odoo solo necesita saber que existe un endpoint al que puede pedirle que envíe un mensaje a un usuario. El servicio expone este endpoint, recibe la información, habla con Firebase y responde indicando si ha podido hacerlo.
Odoo no sabe cómo se envía una notificación push, ni tampoco lo necesita.
Odoo no tiene por qué saber cómo se hace todo
Cuando saco una funcionalidad fuera, intento reducir la relación entre ambas partes a un contrato.
Odoo sabe qué tiene que enviar y qué puede recibir como respuesta. Nada más.
Es parecido a subcontratar un servicio: yo sé qué información tengo que dar y qué resultado espero recibir. No necesito conocer el procedimiento que se va a realizar para que yo obtenga el resultado.
El servicio recibe toda la información que necesita, trabaja con los datos, y me devuelve lo que yo necesito, ya procesado.
Al servicio le da igual quién esté al otro lado: puede ser Odoo 12, Odoo 20 u otra aplicación completamente distinta, siempre que respete el mismo contrato.
El ERP no evoluciona al mismo ritmo que sus integraciones
Cuando una empresa tiene una instalación grande, personalizada y con años de trabajo encima, lo normal es que su ERP permanezca bastante tiempo en la misma versión. Migrarla cuesta tiempo, dinero y pruebas.
Sin embargo, el mundo no para, y el resto del software sigue avanzando: Firebase, DocuSign, Mailchimp, DHL, las APIs bancarias… todo cambia y evoluciona. Las librerías de Python abandonan versiones antiguas y empiezan a utilizar características que antes no existían.
Odoo puede necesitar una versión determinada de una librería porque otra parte del sistema depende de ella, y una integración moderna puede exigir una versión mucho más reciente. Actualizar una rompe Odoo, y mantener la antigua hace imposible instalar la versión actual de la librería.
Si lo separas, te quitas el problema de encima, porque el servicio de Firebase puede utilizar las versiones que necesite Firebase. Si dentro de dos años necesita una versión nueva de Python, se actualiza su contenedor.
Y si mañana migras tu Odoo a otra versión o incluso a otro sistema, el servicio de Firebase tampoco tiene por qué cambiar. El nuevo sistema seguirá haciendo la misma petición y esperando la misma respuesta.
Hay cosas que ahora diseñaría de otra forma
Por todo esto, ahora desarrollaría algunos módulos de forma diferente. Tenemos, por ejemplo, una integración antigua con DHL para generar etiquetas de transporte. La lógica lleva muchos años dentro del ERP y utiliza un sistema basado en archivos que DHL nos proporciona.
Funciona, así que extraerla mañana solo por dejar la arquitectura más bonita no me aportaría gran cosa, pero si tuviera que reconstruirla ahora, no volvería a hacerlo así. Sería mucho mejor que Odoo pidiese la etiqueta a un servicio y este se encargase de proporcionársela, utilizando el mecanismo que DHL soporte en ese momento.
Algunas funcionalidades sí deben vivir en el sistema
Esto tampoco significa que crea que todo deba convertirse en un microservicio, porque hay funcionalidades que pertenecen claramente a Odoo.
Si tienes un módulo que debe trabajar con documentos del sistema, mantener estados y que no depende de nada externo, no le veo sentido a sacarlo a un servicio externo. Ahí el dato y el proceso viven en Odoo y sacarlo solo añadiría comunicación entre sistemas, problemas de sincronización y otra pieza que mantener.
Si algo puede vivir ajeno al ERP, recibir toda la información que necesita, hacer su trabajo y devolver el resultado, me planteo seriamente sacarlo fuera. Si para funcionar necesita conocer permanentemente el estado interno del ERP, probablemente deba quedarse dentro.
Reiniciar un servicio sin parar el sistema entero
Gracias a Docker Compose, este enfoque es sencillo y cómodo. Cada servicio tiene su entorno, sus dependencias y sus logs. Puedo actualizar uno o reiniciarlo sin tener que apagar Odoo.
Si algún servicio ha dejado de funcionar y tienes que diagnosticarlo, puedes ir a sus logs, reiniciarlo para ver si es un error temporal o actualizarlo sin parar el resto del sistema.
A mí este enfoque me resulta muy cómodo y, para el tamaño de nuestra instalación, Docker Compose sigue siendo más que suficiente.
Lo que intentaría sacar fuera antes de una migración
Si mañana tuviera que pasar nuestra instalación actual a una versión moderna, hay integraciones como la de DHL que agradecería haber independizado antes.
Si consigo sacar antes todas esas integraciones, la nueva instalación necesitará muchas menos dependencias ajenas a las propias de Odoo.
Son buenas noticias, porque probablemente solo tenga que asegurarme de que el contrato sigue cumpliéndose, es decir, de que mi sistema envíe lo que tiene que enviar y que efectúe las operaciones que tenga que hacer con el resultado que reciba.
Antes, cuando aparecía una necesidad nueva alrededor de Odoo, pensaba en qué módulo tenía que desarrollar. Ahora, antes de nada, me hago esta pregunta:
¿Esto necesita realmente vivir dentro de Odoo?