Todo lo que he aprendido sobre testing de proyectos de analítica de datos en el mundo real
Los últimos meses hemos estado construyendo las herramientas para que los equipos de datos que trabajan con Tinybird pudieran hacer cambios y asegurar la calidad de los mismos a través de un proceso de integración continua (CI a partir de ahora).
Esta práctica de testear e integrar cambios que está interiorizada en la mayoría de equipos de software, no lo está en los equipos de datos. Todavía hay muchos “single-person data teams” que no tienen capacidad y en las organizaciones con equipos dedicados, depende de diversos factores: desde malas experiencias del pasado, a procesos de migración o la propia cultura de la compañía.
Ha sido una experiencia descubrir en 2024 proyectos grandes en producción, en organizaciones grandes con 0 tests y sin CI
¿Cómo testear un proyecto de analítica de datos?
En un proyecto de analítica de datos normalmente, ingestas datos, los transformas, publicas y durante el proceso necesitas algún mecanismo para hacer tres validaciones:
lógica o funcional
calidad de los datos
performance
Validando la lógica en un proyecto de datos
Validar la lógica consiste en: "dados unos datos que se ingestan y transforman por el pipeline, la salida debe ser determinista de acuerdo a las reglas de negocio implementadas".
La palabra clave es determinista, lo explico más abajo, pero antes la realidad.
Para alguien que se dedica a desarrollar software el “testing funcional” es el pan de cada día, sin embargo, no es habitual verlo implementado en un proyecto de datos.
En muchos casos, la validación funcional es implícita a la propia implementación de la lógica, es decir, conforme escribes las reglas de negocio (supongamos en una consola SQL), validas "a ojo" la salida.
En otros casos las reglas de negocio son "tan sencillas", por ejemplo, simplemente unas pocas agregaciones sobre tablas de eventos, que se considera "overhead" añadir testing: ¿Escribirías un test para validar una operación aritmética? Si tu respuesta es no, no entiendes cómo funciona la analítica de datos.
En otros, hay un equipo de QA o integración testeando el producto final (no el pipeline o el dato).
Y en otros, simplemente desconoces el negocio y los usuarios validan en producción o en el mejor de los casos en staging.
La alternativa a todo esto son tests funcionales que se ejecutan idealmente como parte de un proceso de CI.
Estos tests requieren obviamente de conocimiento del negocio, una estrategia de testing consolidada en la organización y una propiedad que no necesariamente se tiene que dar en un proyecto de analítica de datos.
“dados unos datos que se ingestan y transforman por el pipeline, la salida debe ser determinista de acuerdo a las reglas de negocio implementadas”
Que un pipeline sea determinista, es decir, que devuelva la misma salida para los mismos datos de entrada, puede depender:
de funciones estadísticas que lo sean o no,
o bien se pueden ver afectados por patrones inesperados en la ingesta (registros duplicados, nulos, valores fuera de rango, etc.)
o simplemente se han implementado de manera no determinista (el típico ORDER BY donde no toca).
Más allá de la lógica del pipeline, la automatización de tests funcionales requiere de ciertas herramientas que no están maduras en la industria:
Generación de fixtures que repliquen escenarios del mundo real, por contenido y volumen y permitan validaciones deterministas.
Un entorno aislado de producción donde poder ejecutarlos, de nuevo, de manera determinista.
Con todo esto el testing funcional es un problema en sí, no trivial y no es una parte fundamental del ciclo de desarrollo en equipos de datos.
Como resumen, los tests funcionales acercan la ingenería de datos a la ingeniería de software y es raro, MUY RARO, verlos implementados en el mundo real.
¿Cómo testear la calidad de los datos?
Los datos sirven un propósito dentro de una organización, ya sea servir procesos de "business intelligence" para ayudar en la toma de decisiones, servir analítica a usuarios, procesos de recomendación o <introduce_caso_de_uso>.
La principal diferencia entre un proyecto de datos y uno de software, son los datos y en la mayoría de casos, igual que el software que pones en producción, los datos requieren de ciertas validaciones.
En proyectos de datos operacionales, generalmente la calidad de los datos se valida en la propia base de datos a base de restricciones o el propio diseño relacional, o en una capa de software por encima.
En los proyectos de analítica, debido a su naturaleza y características (altos volúmenes de datos, heterogeneidad, velocidad, transformaciones en streaming, etc.) la validación en la calidad de los datos, cuando se valida, se delega a procesos que ocurren después de la ingesta en producción.
Aquí he visto dos aproximaciones:
Procesos de calidad de los datos. Por aquí una explicación más detallada.
Detección de anomalías. Por aquí algunos ejemplos.
Si no sabes por dónde empezar a validar la calidad de tus datos haz lo siguiente:
Con la herramienta que utilices, valida que no hay nulos o valores vacíos en las columnas de tus tablas durante la última hora.
Ejecuta en una GitHub Action (o cron para los boomers) esa validación cada hora, asegurándote de que te llegue una notificación cuando encuentre algún nulo o valor vacío donde no debería haberlo.
Lo que vas a encontrar te sorprenderá.
Lo siguiente es añadir más casuística: duplicados, valores fuera de rango, outliers, tablas vacías, etc. Con el tiempo vas a tener una suite de tests que te va a ayudar.
Por aquí un ejemplo en el mundo real y otro por acá.
Por contar la batallita, siempre que estoy en soporte en Tinybird algún usuario pregunta algo sobre SQL, asumiendo un error en la herramienta: "¿por qué este pipeline da X resultado cuándo debería dar Y?", el problema, generalmente no es la herramienta ni la SQL, son los datos.
Performance
Otra batallita:
Hace unos cuantos años, un cliente tenía por contrato un SLA en cuanto al performance de las APIs que servían con Tinybird.
La premisa era simple: sus equipos de negocio habían estado sufriendo ya que el sistema de "business intelligence" que usaban para tomar decisiones se había ido degradando con el tiempo hasta el punto que era inusable, cada pequeña revisión de los datos para tomar una decisión requería esperar una cantidad elevada de tiempo.
Cuando decidieron migrar a un sistema de analítica en tiempo real, se introdujo una cláusula en el contrato para cumplir con SLA en cuanto a performance. Eso no sólo era bueno para ellos, sino que nos forzaba a nosotros a construir el producto que queríamos construir.
Para cumplir con el SLA contamos con dos herramientas:
Una pequeña herramienta en la línea de comandos que usabas en tiempo de desarrollo para evaluar performance.
Un sistema de monitorización en producción.
Con el tiempo hemos integrado ambos en Tinybird:
El primero en los procesos de integración continua, lo cual es muy interesante ya que abre la puerta al testing automático.
El segundo a través de paneles de control en el propio dashboard de Tinybird.
De aquí puedo extraer tres lecciones:
El testing de performance no es trivial de implementar, especialmente en tiempo de desarrollo.
Automatizarlo es todavía menos trivial. No por el hecho en sí de hacerlo automático, sino por lo que tiene que comunicar al usuario que hay detrás aplicando un cambio.
Los paneles de control pueden ser útiles en producción, pero su verdadera utilidad debería ser de apoyo a un sistema de alertas.
Un último apunte sobre integración continua
He escrito el blog post como excusa para explicar lo que viene a continuación, ojo que voy.
Testear un proyecto de datos es necesario y testearlo bien es difícil. No sólo se requiere de las herramientas adecuadas, sino también del conocimiento y la voluntad de los equipos.
La realidad de la industria es que no hay equipos y herramientas maduras para hacer testing de proyectos de datos.
Dicho esto y aunque parezca un antagonismo, el mayor dolor en los equipos de desarrollo - durante el proceso de desarrollo - es su proceso de testing e integración continua.
Esto es algo que he vivido en primera persona en todos los equipos en los que he estado y también he visto en la mayoría de equipos de datos que han intentado implantar un proceso de integración continua.
La integración continua es otro producto más y, por lo general, no se trata así dentro de las organizaciones.
Se tiende a degradar muy fácilmente, produciendo flaky tests impredecibles, introduciendo latencias inasumibles en el ciclo de desarrollo, ralentizando el feedback loop, generando frustración y discusiones en los equipos y otros problemas más que estoy seguro que me podrías contar.
Mi consejo y la decisión que tomaría hoy:
Si haces CI, trátalo como un producto más, ten un equipo dedicado a mantener y mejorarlo, es tiempo y dinero bien invertido.
¿Cómo me imagino yo el testing en proyectos de analítica de datos?
Tres premisas:
Los tests son un mal necesario: Las herramientas te tienen que permitir generar fixtures y tests funcionales, conforme desarrollas los pipelines.
La calidad de los datos no es opcional y tiene que ser fácil de configurar o venir por defecto.
Las propias herramientas te deben sugerir y aplicar optimizaciones en los pipelines: desde tipos de datos, pasando por índices, transformaciones, etc.
Y un bonus: La mayoría de equipos de datos hará una aproximación incorrecta a CI, cometiendo los mismos errores que los equipos de software hemos cometido durante años.