Cómo construimos Houyi, nuestro sistema de visualización de riesgo de cambios de código
Gui Lai, del equipo de la plataforma de I+D de Meituan, cuenta cómo construyeron un sistema que analiza cada cambio de código, mapea su cadena de impacto y genera un informe de riesgo automático antes de que llegue a producción.
1. Riesgo y cambio en los sistemas de software
El cambio es el motor de la evolución de un sistema de software, pero también el terreno fértil donde crece el riesgo. Si un sistema deja de iterar y cambiar, gradualmente pierde vitalidad y valor. Pero a medida que el sistema itera, el riesgo de software también se va generando poco a poco, y evitar el riesgo que introducen los cambios es uno de los desafíos más grandes en el área de aseguramiento de calidad. Analizando la arquitectura típica de un sistema de software, podemos identificar tres grandes dimensiones de cambio:
- Cambios de infraestructura: hardware base, red del proveedor, contenedores de servicios en la nube, lenguaje de desarrollo, sistema operativo y clústeres de datacenter. Estas iteraciones de infraestructura mejoran enormemente la capacidad de servicio de la capa base del sistema, pero si un cambio introduce riesgo, el alcance del impacto suele ser grande.
- Cambios externos al sistema: picos repentinos de tráfico de usuarios, cambios en las necesidades de los usuarios, y cambios en servicios y componentes de terceros. Estos hacen que el sistema desarrolle nuevas capacidades de forma continua, pero también aumentan el riesgo de estabilidad.
- Cambios internos del sistema: rotación del equipo técnico, lanzamiento de nuevas funcionalidades, actualización de la arquitectura general. Este es el factor de cambio central que impulsa la evolución del software, y también donde ocurre el riesgo con más frecuencia.
Algunos incidentes típicos de producción causados por riesgo de cambios:
- Un problema en producción causado por un cambio externo: un cable de fibra óptica cortado en excavaciones afectó fuertemente a todo un servicio.
- Un problema típico de cambio de código: un efecto secundario al lanzar una nueva funcionalidad en el sistema de Gmail de Google generó un problema funcional.
- Otro problema típico de cambio de código: al actualizar código muy antiguo, la empresa Knight (Knight Capital) desencadenó una lógica anómala.
- Un problema causado por un cambio de configuración: dio lugar a un incidente de explotación de promociones (“hacer trampa” con cupones).
- Un cambio por error humano: una operación errónea de un desarrollador eliminó todo un conjunto de datos centrales.
En el trabajo real, el riesgo generado por los cambios tiene un impacto muy grande en el negocio. Considerando la escala del negocio de “a domicilio” (到家) de Meituan, con cientos de millones de solicitudes, la posibilidad de que un cambio de sistema genere riesgo se amplifica más aún, y el “efecto mariposa” del riesgo de cambio se vuelve más notorio: un solo problema puntual puede tener un impacto enorme en todo el negocio central de “a domicilio”.
Primero, mirando quién se conecta al negocio de “a domicilio”: internamente incluye delivery de comida, compras rápidas, farmacia y más; externamente hay numerosos clientes empresariales. Segundo, participan muchas partes: usuarios finales, comercios, repartidores y distintas plataformas. Tercero, el negocio está basado en una arquitectura de microservicios, con relaciones de invocación complejas entre servicios y cadenas centrales muy largas. Además, el negocio depende fuertemente de la configuración, así que un problema en un solo eslabón afecta a todas las partes relacionadas.
Por eso, para desarrollo y testing, detectar y evitar el riesgo de calidad que introducen los cambios se vuelve fundamental.
Entonces, ¿dónde está el punto central de trabajo en la construcción de calidad respecto al riesgo de cambios? Analizando problemas históricos de producción, encontramos que la proporción de incidentes causados por cambios internos del sistema es alta, y que esos cambios están relacionada directa o indirectamente con cambios de código. Por eso empezamos a construir nuestro trabajo de calidad alrededor de los cambios de código como factor central.
Después nos hicimos dos preguntas clave:
- ¿Se puede visualizar el riesgo de un cambio de código, para mejorar la capacidad de percepción de testing y desarrollo?
- Alrededor del riesgo de cambio de código, ¿se puede construir un sistema completo de defensa de calidad?
Analizando esto, y apoyándonos en un árbol de características del código, podemos percibir mejor la capacidad de visualización de los cambios de código. Después, a través de cada nodo hoja, identificamos bien todas las características relevantes y aplicamos la estrategia de defensa de calidad correspondiente.
2. Construcción del sistema de visualización de riesgo de cambios de código (Houyi)
El modelo tradicional de testing tiene dos problemas típicos: primero, falta de capacidad de análisis visual integral sobre el código que desarrolla el equipo; segundo, el alcance real del impacto de un cambio de código depende, en la práctica, sobre todo de la experiencia de desarrolladores y QA. Frente a estos problemas del modelo tradicional, quisimos construir el aseguramiento de calidad en tres dimensiones:
- Capacidad de percepción del cambio de código: resolver cómo cubrir el máximo posible de casos de cambio de código, sin importar la forma del código ni el modelo de ingeniería.
- Caracterización del código: extraer distintas características de todo el código modificado, y etiquetarlas según su función.
- Ecosistema de aplicación: sobre las dos capacidades anteriores, construir el ecosistema de escenarios de aplicación correspondiente, integrando la capacidad de caracterizar el riesgo de cambio en distintas etapas del pipeline de testing, para una defensa de calidad continua.
La forma final de esta solución de aseguramiento de calidad sobre riesgo de cambios de código es un sistema de análisis visual de código, que internamente en “a domicilio” bautizamos Houyi (后羿). Como su nombre lo indica —Houyi, el arquero mitológico que derribó los soles—, buscamos que el sistema sea igual de preciso a la hora de evaluar e interceptar riesgos de calidad, mejorando la capacidad de defensa. La arquitectura del sistema tiene cuatro capas:
- Capa de componentes base.
- Capa de análisis de código: resolver el análisis e identificación precisa de cambios de código sin importar su forma.
- Capa de caracterización: el núcleo es el etiquetado estructurado y por características de todo el código.
- Capa de aplicaciones de negocio: en distintos escenarios y etapas, integra la capacidad de visualización del cambio de código, construyendo una capacidad completa de intercepción de riesgo de calidad.
Además, incorporamos herramientas de inteligencia artificial para potenciar todo el sistema. También exponemos las capacidades núcleo mediante una Open API, entregándolas a otras plataformas de herramientas de eficiencia de calidad dentro de Meituan.
En resumen, el flujo clave del sistema visual Houyi se percibe desde dos puntos de entrada en la capa de aplicación: el sitio principal de Houyi, y la plataforma de entrega de ingeniería. A través de mensajería asíncrona detectamos la tarea de análisis y descargamos el código fuente, obteniendo los archivos, métodos y líneas modificadas correspondientes; con capacidad de análisis de bytecode, analizamos los cambios en la cadena de invocación y los guardamos en una base de datos de grafos; después etiquetamos e identificamos características en el código modificado; finalmente generamos un informe de análisis visual que se entrega directamente a QA.
Por supuesto, en todo este proceso de construcción también enfrentamos varios desafíos técnicos.
El primer desafío fue la tecnología de análisis de código. En las primeras etapas usábamos solo análisis de AST para identificar el código, pero teníamos problemas para reconocer expresiones lambda y genéricos de Java. Sobre esa base, incorporamos análisis de bytecode con ASM para resolver esos problemas, pero ASM también tiene sus propias limitaciones con características de reflexión de Java que no puede reconocer. Por eso esperamos incorporar en el futuro tecnología de análisis dinámico de código para resolver el problema de la reflexión.
El segundo desafío técnico fue el almacenamiento masivo de datos relacionales. Al principio usábamos una base de datos relacional para almacenar, pero a medida que el sistema se usaba más y acumulaba una enorme cantidad de datos de topología de cadenas de invocación, el rendimiento de las consultas se volvió muy pobre. Por eso exploramos e incorporamos una base de datos de grafos, lo que resolvió el problema de rendimiento de consultas sobre datos relacionales masivos.
El tercer desafío técnico fue la diversidad de características de riesgo de código. Las características personalizadas están fuertemente ligadas al negocio específico —por ejemplo, características de pérdida de fondos, características de paginación, características de multithreading. Frente a este tipo de características de riesgo, nuestro modelo de desarrollo anterior requería una comunicación profunda entre los desarrolladores del sistema y el QA de negocio para definir la estrategia de identificación, lo cual tenía baja eficiencia de comunicación y ciclos de desarrollo largos.
Por eso mejoramos toda la capacidad, desarrollando un framework de desarrollo componetizado que abrimos a los QA de cada línea de negocio, para que puedan desarrollar sus propios componentes personalizados y cargarlos en Houyi, logrando una identificación rápida de características diversas.
3. Houyi en la práctica
A continuación, nos enfocamos en presentar el estado de la aplicación práctica del sistema. Como muestra el mapa general del ecosistema de aplicaciones de aseguramiento de calidad de Houyi, hoy el sistema tiene construidos ocho escenarios de aplicación núcleo:
- Calibración y diagnóstico a nivel de plan técnico
- Refuerzo de capacidades en la etapa de Code Review
- Evaluación del alcance de impacto de un cambio
- Recomendación de casos de prueba a nivel de interfaz
- Diagnóstico de riesgo de cambios de configuración
- Diagnóstico de riesgo de compatibilidad
- Alerta temprana por características de riesgo de código
- Capacidad de Open API
Primero, el diagnóstico de elementos faltantes en el plan técnico. En el proceso de testing de un proyecto hay principalmente dos puntos de dolor: cuando los desarrolladores escriben el plan técnico, el grado de estandarización suele ser bajo, y la retroalimentación intermedia sobre actualizaciones del plan técnico llega tarde. Pero el plan técnico es un input clave del que depende QA, así que al escribir casos de prueba suele faltar información clave de cambios —definiciones de interfaz, definiciones de ítems de configuración, tareas programadas, mensajes asíncronos, campos de tablas de base de datos— que a menudo no está bien actualizada en el plan técnico.
Frente a esto, Houyi identifica el código y obtiene qué información realmente cambió a nivel de código en este cambio, luego trae el plan técnico correspondiente y lo analiza, hace un diff de los ítems clave de cambio, y genera un informe de diagnóstico de elementos faltantes del plan técnico para QA. QA puede usar este informe para bloquear puntos de control según los ítems de diagnóstico, y también para completar los casos de prueba.
El segundo escenario de aplicación es un nuevo modo mejorado de Code Review. El Code Review tradicional también enfrenta varios puntos de dolor: los desarrolladores suelen enfocarse más en el estilo de código y la razonabilidad del diseño de arquitectura durante el review. Y el modo habitual de Code Review, basado en texto plano, también tiene sus limitaciones: primero, no permite saltar rápido entre el flujo ascendente y descendente del método modificado durante el review; segundo, no muestra la lógica de negocio del método modificado ni de la cadena de invocación de forma visual.
Frente a esto, Houyi construyó un nuevo modo de Code Review impulsado por la visualización de la cadena de cambios, cuyo objetivo central es detectar el riesgo de calidad lo antes posible durante la etapa de Code Review. Su funcionamiento núcleo es que, al revisar un archivo modificado, Houyi extrae rápidamente los métodos y variables modificados en ese archivo, y qué características de riesgo tienen esos métodos y variables, para que QA y RD (desarrollo) capten rápido la información clave del cambio.
Sobre esta base, también ofrecemos la capacidad de saltar rápidamente entre el flujo ascendente y descendente de un método modificado durante el review, entendiendo la relación completa con el resto del negocio; durante ese salto, la lógica del recorrido se dibuja en tiempo real como un grafo de topología de invocaciones, para percibir la relación de lógica de negocio entre métodos modificados y evaluar mejor, desde la perspectiva de toda la cadena, el impacto de este cambio de código —resolviendo bien el punto de dolor de la etapa de Code Review.
El tercer escenario de aplicación es la evaluación del alcance de impacto de un cambio. Hoy Houyi tiene construidas seis capacidades de evaluación del alcance de impacto de un cambio:
- Atributos básicos del código, por ejemplo qué métodos se modificaron.
- Soporte para distintos tipos de proyecto de código: HTTP, RPC, paquetes JAR, etc.
- Identificación de características de riesgo genéricas, por ejemplo problemas de compatibilidad transaccional recursiva.
- Identificación de características de riesgo personalizadas, por ejemplo permisos, características de algoritmos.
- Soporte para el impacto dentro de un solo servicio: cadena de invocación de métodos, características de interfaz, de mensajes, de tareas, etc.
- Evaluación del alcance de impacto entre servicios: cómo es el impacto de la cadena de invocación tanto dentro de un servicio como entre distintos microservicios, con una evaluación de impacto más precisa.
Un ejemplo de evaluación de impacto: cuando una interfaz modificada se ve afectada, ¿cuáles son exactamente los métodos modificados que la afectan río abajo? Podemos ver de forma directa qué métodos nuevos y qué métodos modificados afectan a esa interfaz. ¿Cómo es la relación de topología de invocación entre los métodos afectados río abajo? Con el grafo de topología podemos dibujar rápidamente la cadena de invocación entre todos los métodos modificados debajo de esa interfaz. También podemos evaluar y caracterizar rápidamente el detalle de la cadena de invocación de un método modificado dentro de todos los métodos de la interfaz. Y ofrecemos una vista de análisis de la cadena completa de invocaciones para todos los métodos bajo una interfaz.
El cuarto escenario de aplicación es el diagnóstico de riesgo de cambios de configuración. En negocios grandes y complejos, todo el sistema suele depender fuertemente de la configuración —configuración de lanzamiento gradual (gray release), configuración de degradación, ítems de control de lógica interna— con un impacto grande sobre todo el sistema. Pero QA y desarrollo suelen tener poco control sobre el riesgo de configuración, asumiendo que el código es el foco principal del aseguramiento de calidad, así que los problemas de producción causados por configuración son frecuentes y sus consecuencias suelen ser graves.
Frente a este punto de dolor central, Houyi construyó su capacidad núcleo de riesgo de cambios de configuración en tres niveles:
- En la capa de identificación y análisis de cambios de configuración, identificamos con precisión distintos tipos de configuración: si es nueva o modificada.
- Con la capacidad de evaluación de impacto de Houyi, obtenemos qué interfaces, qué cadenas de impacto, y qué mensajes asíncronos y tareas programadas se ven afectados por la configuración.
- Con la evaluación de impacto ya lista, podemos, a través de testing, cubrir mejor los escenarios de cambio, construyendo así una métrica de cobertura de testing para cambios de configuración. Como nuestra capacidad de percibir los resultados de testing de configuración no era fuerte, construimos, mediante minería y grabación de tráfico, una percepción en tiempo real de la cobertura de testing de configuración. Y a nivel de todo el pipeline, con puntos de control clave sobre cambios de configuración, defendemos mejor contra los problemas que puede causar un cambio de configuración.
El quinto escenario de aplicación es el diagnóstico de riesgo de compatibilidad del lado del servidor. Analizando el conjunto de problemas históricos de producción, encontramos que los problemas típicos de compatibilidad entre versión nueva y vieja tienen una proporción alta. Intentamos resolverlo con Houyi: QA puede identificar problemas de compatibilidad simples, por ejemplo si los parámetros de entrada o el valor de retorno de una interfaz tienen un campo nuevo evidente o un cambio de tipo, eso se detecta claramente.
Pero en el análisis de compatibilidad hay una categoría de cambios menos evidente que también causa problemas de compatibilidad: por ejemplo, restricciones a nivel de parámetros de entrada, un campo que pasa de opcional a obligatorio —este tipo de cambio, en realidad, es muy difícil de percibir a nivel de la definición de código. Otra categoría es cuando el parámetro modificado se arma indirectamente a través de una clase VO invocada internamente; en este caso también es muy difícil para QA percibir el riesgo de compatibilidad de un cambio indirecto en una clase VO interna.
Por eso, frente a este punto de dolor, Houyi construyó capacidades de reflexión y serialización, para captar rápidamente cómo un cambio en una clase VO subyacente afecta a la interfaz correspondiente, generando una alerta temprana de compatibilidad de interfaz. QA usa este informe de diagnóstico para evaluar mejor la compatibilidad correspondiente y planificar el orden razonable de despliegue.
El sexto escenario es la recomendación automática de casos a nivel de interfaz. Para el negocio complejo de “a domicilio”, cómo usar los muchos casos de automatización que acumulamos —¿regresión completa, o selección puntual?— también es un punto de dolor grande. Por eso Houyi, basado en su capacidad de identificar métodos modificados, analizar la cadena de impacto y las interfaces correspondientes, se conecta con la plataforma inteligente de cobertura de código de “a domicilio” y su historial de cobertura de tráfico, para obtener rápidamente la interfaz y los métodos modificados y, con ayuda de la plataforma integral, obtener los casos de automatización correspondientes y hacer una recomendación precisa de casos —construyendo así una solución integral de recomendación de casos.
El séptimo escenario típico es la alerta temprana por características de riesgo de calidad del código. En el proceso de construcción de calidad, solemos encontrarnos con un tipo de escenario especial que necesita validación —por ejemplo, escenarios de pérdida de fondos— donde, además de validar la funcionalidad, hace falta validar escenarios de riesgo personalizados, escenarios anómalos, lógica especial de paginación y escenarios de reintento. Pero es muy difícil detectar este tipo de características de riesgo a lo largo de todo el proceso de código, lo que hace que a veces nos olvidemos de validar los escenarios especiales.
Frente a esto, Houyi construyó su función de identificación de características de riesgo desde dos frentes: primero, el sistema construye por sí mismo un modelo de estrategia de identificación de características de riesgo genéricas; segundo, cada área de negocio también puede construir su propia estrategia de identificación de características de riesgo.
Con esta capacidad núcleo de identificación, integramos las características correspondientes con las plataformas dependientes río arriba y río abajo del proceso de validación, generando estrategias de testing recomendadas según cada característica específica, y conectando todas estas capacidades para construir un esquema sistemático de aseguramiento de calidad basado en características de riesgo de código.
El octavo escenario de aplicación es la capacidad de habilitación mediante Open API. Queremos exponer la información que Houyi analiza e identifica a través de una API abierta, para que otras plataformas de herramientas relacionadas puedan usarla. Hoy, dentro del alcance de “a domicilio”, ya abrimos esta capacidad a seis plataformas núcleo: la plataforma de gestión de interfaces, la plataforma inteligente de cobertura de código, el sistema holográfico, la plataforma de testing de excepciones, el sistema autónomo de entrega de ingeniería, y la plataforma integral de automatización.
4. Planes futuros
Combinando la práctica concreta con la experiencia acumulada, en el futuro vamos a trabajar el aseguramiento de calidad en cuatro direcciones:
- Reforzar la tecnología de análisis de código, esperamos usar tecnología de análisis de cadena dinámica para mejorar la precisión general del análisis.
- Tecnología de identificación de características de riesgo, esperamos apoyarnos en las capacidades de los grandes modelos de lenguaje para el análisis de características de riesgo y la recomendación de estrategias de testing correspondientes.
- Seguir ampliando el ecosistema de escenarios de aplicación, explorando en distintas etapas y escenarios de testing cómo integrar mejor las capacidades de Houyi y potenciar la construcción de calidad de cada negocio específico.
- A largo plazo, esperamos poder ofrecer las capacidades núcleo del sistema al resto del área de testing mediante código abierto.
5. Preguntas y respuestas
P1: ¿Cuánto tarda un informe de análisis? ¿Los informes del mismo proyecto de código son independientes entre sí o están relacionados?
R: Hoy el informe de análisis se genera en 1-2 minutos. El informe se genera a nivel de servicio, según la dimensión de la tarea de iteración; por ejemplo, si un proyecto de iteración tiene 5 cambios de proyectos de código, esos 5 cambios se analizan como un conjunto y se reflejan juntos en el informe.
P2: ¿Cómo se implementa la relación de topología de la cadena de invocación?
R: La topología de la cadena se analiza con tecnología AST y ASM, y se complementa con la relación de la cadena Mtrace en producción.
P3: ¿Se puede identificar la relación entre la cadena de invocación de servicios entre múltiples módulos de microservicios? Por ejemplo, una interfaz HTTP que después llama a varias interfaces de servicios RPC.
R: Sí, se puede identificar esa relación entre módulos de microservicios; por ejemplo, qué interfaces RPC llama río abajo una interfaz HTTP; hoy tenemos esa capacidad de identificación.
P4: Hay muchísimas cadenas de invocación de métodos de bajo nivel, ¿hay alguna estrategia de recomendación para eso? ¿El cambio de base de datos se detecta escaneando el Mapper?
R: Hoy, para la cadena de invocación, hacemos un etiquetado de características de riesgo; por ejemplo, si la cadena incluye características de pérdida de fondos, características de configuración, etc. Con esas etiquetas de riesgo, el usuario percibe mejor el nivel de riesgo de la cadena, lo cual da información clave para recomendar la estrategia de testing posterior. Hoy, el cambio de base de datos se identifica escaneando el Mapper, basado en el framework de desarrollo de base de datos MyBatis.
P5: Sobre la recomendación de casos, ¿recomienda casos de una sola interfaz o combina en escenarios de interfaces múltiples?
R: Hoy recomendamos casos de una sola interfaz; por ejemplo, si esta interfaz modificada está asociada a 10 casos de automatización, recomendamos esos 10 casos.
P6: ¿Cuánto tiempo lleva analizar un proyecto en general?
R: Hoy lleva 1-2 minutos.
P7: En la aplicación real, ¿cuál es el principal beneficio?
R: El principal beneficio viene de la aplicación de los ocho escenarios: todos aportan valor de calidad y eficiencia. Por ejemplo, en problemas de compatibilidad ya interceptamos con éxito varios incidentes de calidad de compatibilidad; en la evaluación de riesgo de cambios de configuración, ya interceptamos con éxito varios problemas causados por errores de codificación en valores por defecto de configuración e inconsistencias entre configuración de producción y de entornos inferiores.
P8: ¿Esta plataforma afecta la disponibilidad de los servicios en producción?
R: Hoy esta plataforma no afecta la disponibilidad de los servicios en producción; al analizar el entorno de producción, la operación núcleo es descargar el paquete JAR desplegado correspondiente, sin afectar la disponibilidad del servicio real.
P9: ¿Este sistema tiene un “foso” defensivo? ¿Cuál es el beneficio del sistema? ¿Ayuda al negocio? ¿Cómo se ve reflejado en el negocio?
R: Sobre el “foso” defensivo: la tecnología subyacente de análisis de cambios se basa sobre todo en tecnologías genéricas como AST y ASM; el núcleo del desafío técnico está en la compatibilidad con distintas formas de escribir código de negocio y en la precisión de identificación de características de escenarios de negocio.
El beneficio principal está concentrado en la evaluación de riesgo del alcance de impacto de negocio que trae un cambio, y en la intercepción efectiva de riesgo de calidad; hoy ya interceptamos con éxito varios bugs de evaluación imprecisa de alcance de impacto en interfaces, bugs relacionados con cambios de configuración, bugs de compatibilidad, etc.
En cuanto a la ayuda al negocio: primero, los ocho escenarios de aplicación mejoran la calidad y la eficiencia en general; segundo, mejora la eficiencia para entender el negocio —por ejemplo, con la capacidad de visualizar la cadena de invocación río abajo de una interfaz, se puede entender rápidamente esa relación de negocio.
P10: Cuando la topología de la cadena es demasiado grande, ¿cómo se resuelve? Como distintos servicios usan distintos lenguajes, ¿hay alguna recomendación de tecnología de bytecode?
R: Cuando la topología de la cadena es demasiado grande, se puede agrupar la cadena para mejorar la visualización. Como el stack tecnológico de Meituan es Java, el foco está en avanzar la capacidad de identificación en Java; el análisis de servicios en otros lenguajes lo seguiremos atendiendo y resolviendo a futuro.
P11: ¿Se puede analizar el impacto sobre los servicios río arriba y río abajo?
R: Sí.
P12: Al analizar un cambio de código, ¿cómo se identifica un cambio efectivo de uno no efectivo?
R: Por ejemplo, si se modifica un fragmento de código que no tiene ningún invocador, lo llamamos “código preinstalado” (código muerto o de reserva). Este tipo de código es muy difícil de validar con escenarios de negocio durante testing, y es muy probable que, al pasar a producción, introduzca riesgo latente. Hoy, con el análisis de cambios en la cadena, podemos identificar de forma efectiva este tipo de riesgo de código preinstalado.
P13: ¿En qué etapas se usa el sistema? ¿En la etapa de admisión o en la de salida?
R: Hoy el sistema se puede usar tanto en la etapa de admisión como en la de salida, sin restricción estricta.
P14: ¿Cuánto ruido tienen los problemas identificados?
R: En cuanto al ruido, hicimos muchas optimizaciones de estrategia para mejorar la tasa de identificación; por ejemplo, la tasa de identificación de interfaces HTTP/RPC hoy supera el 98%, y el ruido está bien controlado.
Adaptación del artículo original de Gui Lai (桂来), de la plataforma de I+D de Daojia (到家) en Meituan, “代码变更风险可视化系统建设与实践”, publicado en el blog técnico de Meituan.