Xavier Val

Xavier Val

Ingeniero informático por la Universidad de Alicante. Actualmente trabaja como Quality Assurance Manager en el área de AI & Big Data de Telefónica Tech. Apasionado de la tecnología en todos sus niveles, desde el software hasta el diseño y pilotaje de drones de carreras. En su trabajo como QA Manager, Xavier se encarga de garantizar la calidad de los productos y servicios de Telefónica Tech. Para ello, utiliza sus conocimientos técnicos y su experiencia en las pruebas de software.



AI & Data
De cuando la IA sugiere y los humanos no cuestionan
Una historia de humanos, IA y errores evitables Nadie se sorprenderá al decir que estamos en un mundo cada vez más digitalizado y en búsqueda constante de la eficiencia. Y que vemos muchas bondades y posibilidades de hacer muchas más tareas con mejores beneficios usando sistemas de IA como ChatGPT o GitHub Copilot. Éstas y otras herramientas se han vuelto indispensables para muchos profesionales en distintas áreas. En este post me gustaría mostrar cómo sería llevar a cabo una sencilla tarea con su ayuda y los riesgos a los que nos podemos enfrentar si no somos conscientes de lo que realmente estamos haciendo. Imaginemos que nuestro desarrollador humano de software, al que llamaremos Elon, es una persona que confía plenamente en estas herramientas para agilizar su trabajo. Pero, ¿qué sucede cuando esa confianza se vuelve ciega? Elon está a punto de descubrirlo en sus propias carnes. Una tarea sencilla Estamos en un sprint crucial del ciclo de añadir nuevas funcionalidades a un proyecto que van usan varios clientes para ofrecer sus productos. A Elon se le encarga la tarea de implementar dos funciones de código que van a ser usadas para el cálculo de descuentos sobre los pedidos de los clientes. Como tiene muchas otras tareas que atender va a usar una de sus herramientas favorita, Copilot. Tras leer la escasa documentación de la que dispone y cuál es el cometido de su misión define estos prompts o instrucciones que va a usar para solicitar lo que necesita a la IA y la respuesta de la herramienta: Prompt 1: Prompt 2: ■ Aquí lo que hace el código es calcular un porcentaje de descuento a cada producto de un carrito de la compra, y luego hace la suma de todas las líneas de productos con sus descuentos. Como Elon es un rápido lector de código, acepta el código sugerido por Copilot sin revisarlo a fondo. Por suerte en su proyecto no se acepta código que no tenga pruebas unitarias con lo que su PR (Pull request o solicitud de añadir código) ha sido rechazada de forma automática. Con lo que Elon tiene que añadir pruebas a su código antes de poder marcar su tarea como completada. Ni corto ni -poco- perezoso Elon, que tiene todo el contexto disponible en su IDE, decide pedírselo a Copilot: class TestApplyDiscount(unittest.TestCase): def test_apply_discount(self): cart = [ {'price': 100, 'discount': 10}, {'price': 50, 'discount': 5}, {'price': 75, 'discount': 15} ] self.assertEqual(apply_discount(cart), 202.5) cart = [ {'price': 200, 'discount': 20}, {'price': 100, 'discount': 10} ] self.assertEqual(apply_discount(cart), 240) cart = [ {'price': 50, 'discount': 0}, {'price': 75, 'discount': 0} ] self.assertEqual(apply_discount(cart), 125) cart = [ {'price': 0, 'discount': 50} ] self.assertEqual(apply_discount(cart), 0) cart = [ {'price': 100, 'discount': 100} ] self.assertEqual(apply_discount(cart), 0) ■ Con este código lo que está generando la IA son escenarios de prueba. En cada carrito (cart) hay una serie de artículos y un descuento. En la línea inferior simplemente ha calculado cual sería el precio de ese carrito con los descuentos correspondientes aplicados. En caso de que haya una discrepancia entre lo que espera que sea el resultado y lo que ha devuelto realmente se producirá un error, porque los valores no se corresponden. Añadió las pruebas propuestas a su código sin mucha revisión pero ¡oh!, sorpresa: los propios tests que la IA ha generado en sus pruebas dan error. La primera pregunta a la que se enfrenta Elon es: ¿estará fallando el código de la función el código del test? No le queda otra opción que ponerse a mirar qué es lo que está pasando en su código. Tras revisar las pruebas y entendiendo dónde está el desajuste de resultados entre lo que hace la función y el resultado esperado, descubre que el problema está en el propio test, que el número que espera como resultado no es correcto. Para revisar los escenarios de las pruebas se ha hecho una tabla con los resultados que espera y los que tiene debe devolver el código: Pero el test proporcionado indica que la salida es 202,5 self.assertEqual(apply_discount(cart), 202.5) Y ahora Elon cargado de razón avisa a Copilot de que hay un error en el cálculo que está esperando el test, pero esta IA es un poco testaruda y tras dos infructuosos intentos, Elon tiene copiar el código que la misma IA ha generado previamente para que termine de “creérselo y entender el problema”. Finalmente detecta donde está el error: Ahora ya su código pasa los test proporcionados y puede volver a enviar el código a revisión. Imaginemos que en este proyecto que ha sufrido varios recortes, no dispone de ningún desarrollador más que el propio Elon y que no dispone de un departamento de calidad de software (QAs) que puedan revisar y asegurar el nuevo código entregado, por lo que el código pasa a producción. Semanas después, descubren en un foro especializado en descuentos que se está compartiendo un artículo de cómo un visitante de una tienda puede explotar un error en código y conseguir grandes descuentos en el proceso de compra. El código que era inicialmente inofensivo, o que al menos lo parecía, contenía una (o varias) vulnerabilidades de las que Elon se dio cuenta y que con una simple revisión consciente podría haber evitado este desastre. ¿Por qué caemos en esta trampa? Elon reflexiona sobre por qué confió ciegamente en la IA. La presión por entregar rápidamente, la percepción de que la IA es infalible y el deseo de ser más productivo lo llevaron a bajar la guardia. Se da cuenta de que no está solo; muchos de sus colegas han caído en la misma trampa, seducidos por la aparente infalibilidad de la tecnología. Cómo evitar caer en la trampa Determinado a no repetir el error, Elon lidera un cambio en su equipo. Implementan un proceso de revisión de código más riguroso, especialmente para el código generado por IA. Establecen sesiones de pair programming con desarrolladores de otros proyectos y fomentar una cultura de cuestionamiento constructivo. Elon aprende que la clave está en ver a la IA como una herramienta poderosa, pero no infalible, que requiere supervisión humana. La generación y uso de tests en el proceso de desarrollo ayuda a entender la funcionalidad y poder simular el uso que puede encontrar por los distintos tipos de usuarios cuando el software esté en producción. Continuando con el ejemplo que no ha tenido en cuenta o que podrían ser explotados son los valores negativos en los descuentos o que la suma total nunca debería ser un valor negativo porque implicaría devolver dinero a un cliente que está comprando elementos, con lo que la pérdida para la empresa sería doble: uno por no cobrar los artículos, y otro por estar regalando dinero a quien compra sus artículos. La lección aprendida y el futuro Meses después, Elon observa cómo su equipo ha evolucionado. La colaboración entre humanos e IA es más fluida y segura. Comprenden que el verdadero poder reside en combinar la creatividad y el juicio crítico humano con la eficiencia de la IA. Elon se da cuenta de que este equilibrio no solo mejora la calidad del software, sino que también los prepara para un futuro donde la simbiosis entre humanos y máquinas será cada vez más crucial. Bonus Track ¿Te gustaría saber qué habría pasado si le hubiéramos dado esta misma tarea a un desarrollador bajo la misma presión de tiempo e información? Para saberlo, le he pedido a un amable colaborador que haga el mismo ejercicio disponiendo de la misma información de la que disponía la IA y también que no tardara más de veinte minutos. Obviamente la IA tardó menos, pero creo que vale la pena ver el resultado: lo podéis consultar vosotros mismos en este repositorio. Ahí podréis comprobar las diferencias de cómo la IA puede hacer cosas mejor o peor que un humano, y también cómo un código realizado por un humano tendrá sesgos y gustos personales. En eso se basa la personalización del código, en saber qué se está haciendo para personalizarlo a tu gusto y tener el control. Si no se revisan correctamente los resultados, y no se entiende lo que se está adoptando, una mejora puede tener consecuencias catastróficas.
3 de febrero de 2025
AI & Data
"Tu vuelo ha sido cancelado por motivos operativos": ¿¡Cómo!?
Tres días sumidos en el caos, pérdidas económicas millonarias y miles de pasajeros afectados por “motivos operativos”. Dicho de otra forma, por un bug en el software de los controladores aéreos de Reino Unido. ¿Cuál fue el fallo? El fallo se produjo en el software FPRSA-R que se utiliza para gestionar los vuelos que entran y salen del espacio aéreo de Reino Unido. Esto provocó que NATS (National Air Traffic Services), la organización que se encarga de gestionar y controlar el tráfico aéreo en el espacio aéreo del Reino Unido, tuviera que reducir la capacidad del sistema de control de tráfico aéreo. En consecuencia, provocó la cancelación de cientos de vuelos y retrasos de miles de otros. ¿Se podría haber evitado? El informe preliminar del incidente dice claramente que el fallo pudo haberse evitado si NATS hubiera implementado un proceso de pruebas más riguroso. El proceso de pruebas de NATS no detectó el fallo antes de su puesta en producción y había estado operando con el subsistema FPRSA-R de forma continua desde octubre de 2018 procesando más de 15 millones de planes de vuelo sin incidencias y no se había realizado ninguna actualización reciente que hubiera podido introducir el error. ¿Cuál fue el origen del error? Para entender si el plan de pruebas de NATS era lo suficientemente riguroso o no, habría que analizarlo y ver si en las especificaciones se definía el proceso que generó el fallo y si ese caso estaba cubierto o no por las pruebas. Pero hay que entender el origen del error para saber cómo podría haberse evitado: El software de gestión de planificación de vuelos de NATS (FPRSA-R) es el encargado de registrar y autorizar todo vuelo que entra y sale del espacio aéreo de Reino Unido. En un primer momento la prensa comunicó que el error se desencadenó a causa del vuelo BAW231, un vuelo de British Airways que cubría la ruta Londres-Nueva York. El vuelo despegó del aeropuerto de Heathrow a las 10:00 hora local del 29 de mayo de 2023 y pudo aterrizar en el aeropuerto de Nueva York sin incidentes. El plan de vuelo enviado al sistema de NATS contenía una línea vacía en el campo "hora de llegada". Pero según indican los foros de aficionados y profesionales aeronáuticos en Reddit, el origen del error fue el vuelo FBU731 de French Bee desde Los Angeles USA a Orly en Francia. Su plan de vuelo enviado al sistema de NATS contenía un punto de la ruta (waypoint) duplicado. ⚠️ En cualquiera de los posibles casos mencionados, ya sea porque el origen de una línea vacía o de un punto de la ruta duplicado, ambos escenarios deberían haber sido probados entre otros muchos para comprobar la robustez y la respuesta del sistema en caso de no recibir la entrada esperada y evitar que el sistema FPRSA-R de NATS se bloqueara. ¿Qué pasa si hay un error en un sistema crítico? Un sistema crítico ha de tener una o varias réplicas, que aseguren que, si una máquina/sistema deja de estar operativo, siempre haya otra/s de respaldo, con los mismos datos disponibles para seguir procesando la información pendiente. Las posibles redundancias y distribuciones de sistemas y datos pueden dar para otro post completo, pero lo importante en estos sistemas es que siempre exista un plan alternativo por si se produce un fallo en el sistema. Hay contingencias a muchos niveles, pero las que podrían afectar a un sistema como el de NATS podrían ser por software, hardware, instalaciones (cortes de suministros, sabotajes o inclemencias meteorológicas) o incluso a nivel continental (guerras o bloqueos). El objetivo es que puedan seguir funcionando antes las adversidades o al menos minimizar la posible pérdida de información o seguir con la función que realiza. El sistema encargado de procesar la lista de planes de vuelo pendientes para autorizar se encontró con este plan erróneo o mal formado, no pudo procesarlo y el sistema se bloqueó, levantando una excepción crítica y entrando en modo mantenimiento. Esto hacía que el sistema dejara de estar operativo y el plan de vuelo pendiente de autorizar. El sistema de respaldo asume el rol de procesar el siguiente plan de vuelo pendiente (el que no había podido ser procesado) y hacía el mismo intento y también se bloqueaba hasta que todos los posibles ejecutores de la tarea se bloquearon por el mismo motivo. Los técnicos en un primer momento intentaron reiniciar el sistema, pero no se podía volver a la normalidad. El tiempo corría y el plazo de cuatro horas para iniciar la introducción manual (y lenta) de planes de vuelo había empezado. ¿Posibles soluciones? Los ingenieros de soporte, al no poder restaurar el servicio, solicitaron ayuda al fabricante del sistema. Con el conocimiento del sistema descubrieron el origen del error y las posibles soluciones: Extraer ese plan de vuelo de la lista. Desarrollar una actualización que corrigiera el error en el sistema. La solución sería sacar ese plan y avisar al operador para autorizarlo (o no) de manera manual, mientras el resto de las autorizaciones continuaba. ¿Qué lecciones se pueden aprender? El fallo del control del tráfico aéreo de NATS es un recordatorio de la importancia de la calidad del software. Las empresas que utilizan software crítico deben asegurar que el software desarrollado se prueba de manera exhaustiva contemplando tanto casos de entrada de datos válidos para funcionar, pero también es importante probar como va a responder ante casos inválidos o inesperados. Sería costoso en tiempo y en esfuerzo validar los posibles escenarios de un sistema que se validará. Pero existen muchas aproximaciones para hacerlo. Una de las pruebas de cálculo matemáticos es agrupar escenarios similares, así se probar con muestras de valores que representan a todo su grupo casuístico. Un ejemplo para entenderlo fácilmente sería probar una funcionalidad que recibe como entrada un parámetro, un número que debe estar entre 0 y 100 para realizar ciertos cálculos matemáticos. Una primera aproximación en este escenario sería agrupar los escenarios en distintos grupos como, por ejemplo: Los valores positivos válidos (0≥x≥100) y seleccionar algunas muestras [3, 17, 80] Los valores positivos inválidos (100<x) y probar con algunas muestras [150, 500, 9999] Los valores negativos inválidos (x<0) y sus muestras [-10, -33, -5555] Los valores frontera, que son los escenarios que están en el límite de los válidos y los inválidos, y deberíamos dividirlos entre los que se esperan que sean válidos e inválidos: VF-Válidos: [0, 1, 99, 100] VF-Inválidos: [-1, 101] Valores incorrectos, que serían los casos de introducción de valores de otro tipo al esperado como, por ejemplo: [a, Z, @, ™, “105 OR 1=1”, etc. ] Así, hemos pasado de tener infinitos posibles casos a unas 20 muestras posibles para una cobertura de escenarios muy alta. Y si además se hace con pruebas automáticas que seleccionan la muestra de cada grupo de manera dinámica incluso se disparan el número de casos probados con el mínimo esfuerzo. Otra aproximación utilizada es evaluar cuáles son los mayores riesgos del software y cuáles son los escenarios más críticos con la funcionalidad que se debe cubrir. En esos casos se identifican y priorizan para tener cubiertos los más importantes y poder probar dentro del espacio y los recursos que se hayan asignado a la fase de validación. ✅ En el mundo de las pruebas de software cuanto más tarde se encuentre el error mayor será el coste de reparación. Por ello se invierte mucho esfuerzo que la calidad de los productos entregados tenga fases de validación en la que se asegure que la funcionalidad a entregar sea la que se ha especificado y se haya confirmado que cumple con las expectativas funcionales y no funcionales (accesibilidad, cantidad de usuarios soportada, tiempos de carga o respuesta, robustez, resiliencia, etc.). ¿Cómo lo hacemos en Telefónica Tech? En nuestra área tenemos proyectos muy diversos con el nexo común de usar los datos que tenemos disponibles como operador. Tenemos proyectos que van desde ayudar a que nuestros clientes no sean víctimas de fraudes al pagar en comercios con SmartDigits. Hasta otros proyectos en los que ayudamos a las entidades públicas a la toma de decisiones basada en datos. Con los datos de movilidad de SmartSteps podemos entender cómo se mueve la población para que su experiencia en movilidad sea la mejor posible ayudando a planificar o mejorar los servicios acordes a la demanda real. Siempre con la seguridad de que los datos son anonimizados y agregados para respetar la privacidad de todos los usuarios. Para validar todos estos proyectos a nivel funcional usamos una estrategia común de trabajo y compartimos las mismas herramientas para que podamos reutilizar los conocimientos adquiridos y que la forma de trabajo sea parecida independientemente del proyecto. Esto nos permite centrar nuestro esfuerzo en conocer a fondo la funcionalidad y validarla de la mejor manera posible. ◾ Si estás interesado en saber sobre este mundo, te recomiendo que investigues sobre BDD (Behaviour Driven Development) que es una metodología de desarrollo guiado por comportamiento, para nosotros es una parte fundamental de nuestro proceso de validación funcional. Tras leer todo esto creo que ahora podrás entender este chiste: Un tester entra a un bar nuevo y pide una cerveza, pide ⌀ cervezas, pide 99999999 cervezas, pide una lagartija, pide -1 cerveza y pide una asgdhfk. El primer cliente real entra al mismo bar y pregunta dónde está el baño. El bar explota. Cloud Modernización de aplicaciones en AWS: aprovechando la nube para impulsar la escalabilidad, eficiencia y agilidad 30 de noviembre de 2023
11 de enero de 2024