En ciencias de la computación, la robustez es la capacidad de un sistema informático para hacer frente a errores durante la ejecución y a entradas erróneas. Esto abarca muchas áreas, incluyendo la programación robusta, el aprendizaje automático robusto y el diseño de redes robustas. Técnicas formales, como las pruebas de fuzzing, son esenciales para demostrar la robustez, ya que implican probar con entradas inválidas o inesperadas. Alternativamente, se puede utilizar la inyección deliberada de fallos para probar la robustez, y varios productos comerciales realizan pruebas de robustez del análisis de software.
Construir sistemas robustos que cubran todos los posibles puntos de fallo es difícil debido a la gran cantidad de entradas posibles y combinaciones de entradas. Dado que las pruebas exhaustivas de todos los casos son poco prácticas, los desarrolladores generalizan los casos de prueba. Por ejemplo, al probar entradas enteras, un desarrollador podría seleccionar un número negativo, cero y un número positivo para representar todo el conjunto de los reales. Este método es más eficiente pero más propenso a fallos. Generalizar los casos de prueba es una técnica para lidiar con fallos debidos a entradas de usuario inválidas, pero los sistemas también pueden fallar por otras razones, como desconexiones de red. Independientemente, los sistemas complejos deben manejar cualquier error con elegancia, y algunos de los sistemas más robustos son evolutivos y se adaptan fácilmente a nuevas situaciones.
Desafíos para lograr la robustez
Los programas y el software son típicamente herramientas centradas en tareas específicas, lo que los hace menos generalizados y flexibles que sistemas como internet o los sistemas biológicos, que se adaptan a sus entornos. Una forma en que los sistemas biológicos logran la adaptación es mediante la redundancia. Por ejemplo, los humanos generalmente solo necesitan un riñón, pero tener un segundo proporciona margen para el fallo. Este principio se puede aplicar al software, pero con desafíos. Añadir código a ciegas no se recomienda, ya que introduce más errores, aumenta la complejidad y dificulta la comprensión del sistema. El nuevo código debe poseer una funcionalidad equivalente para que, si una función falla, otra pueda reemplazarla, utilizando diversidad de software manual o automatizada. Esto requiere lógica adicional para saber cómo y cuándo acomodar el punto de fallo, lo que aumenta la complejidad del sistema. Los desarrolladores deben equilibrar la redundancia con la complejidad. Actualmente, las prácticas de ciencias de la computación tienden a centrarse en la escalabilidad y la eficiencia en lugar de construir sistemas robustos, en parte porque la robustez es difícil de lograr de manera general.
Programación robusta
La programación robusta es un estilo que se centra en manejar la terminación inesperada y las acciones inesperadas con elegancia, mostrando mensajes de error precisos e inequívocos que ayuden a los usuarios a depurar programas. Se guía por varios principios:
- Paranoia: El programador asume que los usuarios intentarán romper el código y que su propio código puede fallar o funcionar incorrectamente.
- Estupidez: El programador asume que los usuarios intentarán entradas incorrectas, falsas o malformadas. En consecuencia, el programador devuelve mensajes de error inequívocos e intuitivos que no requieren buscar códigos de error, con el objetivo de ser lo más preciso posible sin ser engañoso.
- Implementos peligrosos: Los usuarios no deberían tener acceso a bibliotecas, estructuras de datos o punteros a estructuras de datos. Esta información debe ocultarse para prevenir modificaciones accidentales que puedan introducir errores. Cuando las interfaces se construyen correctamente, los usuarios las utilizan sin encontrar lagunas, centrándose únicamente en su propio código.
- No puede ocurrir: Las modificaciones del código pueden introducir la posibilidad de que ocurra un caso "imposible". Se asume que tales casos son altamente improbables, y el desarrollador implementa el manejo correspondiente para ellos.
Aprendizaje automático robusto
La robustez en el Machine learning generalmente se refiere a la estabilidad de los algoritmos. Para que un algoritmo de aprendizaje automático se considere robusto, o bien el error de prueba debe ser consistente con el error de entrenamiento, o bien el rendimiento debe permanecer estable después de añadir ruido al conjunto de datos. Con el auge del Deep learning, ha habido un creciente interés en la robustez de las redes neuronales, particularmente debido a su vulnerabilidad a los ataques adversariales. La investigación en esta área a menudo implica técnicas como el entrenamiento adversarial, donde los modelos se entrenan con entradas perturbadas para mejorar la resiliencia. El campo tiene conexiones con el trabajo de investigadores como Aleksander Madry, que ha estudiado la robustez adversarial, y Thomas G. Dietterich, que ha explorado los códigos de salida de corrección de errores y el aprendizaje robusto.
Diseño de redes robustas
El diseño de redes robustas es el estudio del diseño de redes frente a demandas variables o inciertas. Similar al diseño de software, la robustez en el diseño de redes es amplia debido a las vastas posibilidades de cambios o entradas. Implica crear redes que puedan mantener el rendimiento y la conectividad bajo diferentes condiciones de tráfico o fallos. Esta área es relevante para los proveedores de infraestructura en la nube como Amazon Web Services, Microsoft Azure y Google Cloud, que deben garantizar un servicio confiable a pesar de cargas variables y posibles fallos de hardware.
Algoritmos robustos
Existen algoritmos que toleran errores en la entrada. Estos algoritmos están diseñados para producir salidas correctas o aceptables incluso cuando los datos de entrada contienen ruido, valores atípicos u otras imprecisiones. Esto es particularmente importante en campos como la visión por computadora y el procesamiento de señales, donde los datos del mundo real suelen ser imperfectos. Los algoritmos robustos pueden utilizar métodos estadísticos para identificar y reducir el peso de los valores atípicos, o pueden diseñarse teniendo en cuenta la redundancia, similar a los principios de la programación robusta.
Véase también
- Tolerancia a fallos
- Programación defensiva
- Requisito no funcional