Un error de software es un defecto de diseño ( bug ) en el software de una computadora . Un programa de computadora con muchos errores o errores graves puede describirse como defectuoso .
Los efectos de un error de software varían desde menores (como una palabra mal escrita en la interfaz de usuario ) hasta graves (como fallas frecuentes ).
En 2002, un estudio encargado por el Instituto Nacional de Estándares y Tecnología del Departamento de Comercio de Estados Unidos concluyó que "los errores de software son tan frecuentes y tan perjudiciales que cuestan a la economía estadounidense unos 59.000 millones de dólares anuales, o alrededor del 0,6 por ciento del producto interno bruto". [1]
Desde la década de 1950, algunos sistemas informáticos han sido diseñados para detectar o corregir automáticamente diversos errores de software durante sus operaciones.
El metamorfismo de errores (del griego meta = "cambio", morph = "forma") se refiere a la evolución de un defecto en la etapa final de la implementación de un software. La transformación de un "error" cometido por un analista en las primeras etapas del ciclo de vida del desarrollo de software, que conduce a un "defecto" en la etapa final del ciclo, se ha denominado 'metamorfismo de errores'. [2]
Las diferentes etapas de un error en el ciclo de desarrollo pueden describirse como equivocación, [3] : 31 anomalía, [3] : 10 falla, [3] : 31 falla, [3] : 31 error, [3] : 31 excepción, [3] : 31 caída, [3] : 22 falla, bug, [3] : 14 defecto, incidente, [3] : 39 o efecto secundario.
Los errores de software se han relacionado con desastres.
A veces, el uso de la palabra "bug" para describir el comportamiento del software es polémico debido a la percepción. Algunos sugieren que se debería abandonar el término y reemplazarlo por "defecto" o "error" .
Algunos sostienen que el término error implica que el defecto surgió por sí solo y presionan para que se utilice en su lugar el término defecto, ya que connota más claramente que fue causado por un ser humano. [8]
Algunos sostienen que el error puede utilizarse para encubrir una decisión de diseño intencional. En 2011, después de recibir el escrutinio del senador estadounidense Al Franken por registrar y almacenar las ubicaciones de los usuarios en archivos no cifrados, [9] Apple calificó el comportamiento como un error. Sin embargo, Justin Brookman, del Centro para la Democracia y la Tecnología, cuestionó directamente esa descripción, afirmando: "Me alegra que estén solucionando lo que llaman errores, pero no estoy de acuerdo con su rotunda negación de que rastreen a los usuarios". [10]
Prevenir errores lo más pronto posible en el proceso de desarrollo de software es un objetivo de inversión e innovación. [11] [12]
Los lenguajes de programación más nuevos tienden a estar diseñados para evitar errores comunes basados en vulnerabilidades de lenguajes existentes. Las lecciones aprendidas de lenguajes más antiguos, como BASIC y C, se utilizan para informar el diseño de lenguajes posteriores, como C# y Rust .
Los lenguajes pueden incluir características como un sistema de tipos estáticos, espacios de nombres restringidos y programación modular . Por ejemplo, para un lenguaje compilado y tipado (como C ):
número flotante = "3";
es sintácticamente correcto, pero no supera la comprobación de tipos, ya que el lado derecho, una cadena, no se puede asignar a una variable de punto flotante. La compilación falla, lo que obliga a corregir este defecto antes de que se pueda reanudar el progreso del desarrollo. Con un lenguaje interpretado, no se produciría un error hasta más tarde, en el tiempo de ejecución.
Algunos lenguajes excluyen características que fácilmente conducen a errores, a costa de un rendimiento más lento; el principio es que, por lo general, es mejor escribir código más simple, más lento y correcto que código complicado y lleno de errores. Por ejemplo, Java no admite la aritmética de punteros, que, por lo general, es rápida, pero se considera peligrosa; es relativamente fácil provocar un error importante.
Algunos lenguajes incluyen funciones que agregan sobrecarga de tiempo de ejecución para evitar algunos errores. Por ejemplo, muchos lenguajes incluyen una verificación de límites de tiempo de ejecución y una forma de manejar condiciones fuera de límites en lugar de fallas.
Un lenguaje compilado permite detectar algunos errores tipográficos (como un identificador mal escrito) antes del tiempo de ejecución , lo cual ocurre antes en el proceso de desarrollo de software que en el caso de un lenguaje interpretado .
Las técnicas de programación como el estilo de programación y la programación defensiva tienen como objetivo evitar errores tipográficos.
Por ejemplo, un error puede deberse a un error tipográfico relativamente menor (error tipográfico) en el código. Por ejemplo, este código ejecuta una función foo
solo si condition
es verdadero.
si (condición) foo();
Pero este código siempre se ejecuta foo
:
si (condición); foo();
Una convención que tiende a prevenir este problema en particular es requerir llaves para un bloque incluso si tiene solo una línea.
si (condición) { foo();}
La aplicación de las convenciones puede ser manual (es decir, mediante revisión de código ) o mediante herramientas automatizadas.
Algunos sostienen que escribir una especificación de programa que establezca el comportamiento de un programa puede prevenir errores.
Algunos sostienen que las especificaciones formales son poco prácticas excepto para los programas más cortos, debido a problemas de explosión combinatoria e indeterminación .
Uno de los objetivos de las pruebas de software es encontrar errores.
Las mediciones durante las pruebas pueden proporcionar una estimación de la cantidad de errores que probablemente persistan. Esto se vuelve más confiable cuanto más tiempo se prueba y desarrolla un producto. [ cita requerida ]
El desarrollo ágil de software puede implicar lanzamientos frecuentes de software con cambios relativamente pequeños. Los defectos se revelan mediante la retroalimentación de los usuarios.
Con el desarrollo basado en pruebas (TDD), las pruebas unitarias se escriben mientras se escribe el código de producción, y el código de producción no se considera completo hasta que todas las pruebas se completen con éxito.
Las herramientas para el análisis de código estático ayudan a los desarrolladores a inspeccionar el texto del programa más allá de las capacidades del compilador para detectar problemas potenciales. Aunque en general el problema de encontrar todos los errores de programación dada una especificación no tiene solución (ver problema de detención ), estas herramientas explotan el hecho de que los programadores humanos tienden a cometer ciertos tipos de errores simples a menudo al escribir software.
Las herramientas para supervisar el rendimiento del software mientras se ejecuta, ya sea específicamente para encontrar problemas como cuellos de botella o para garantizar que funciona correctamente, pueden estar incorporadas en el código de forma explícita (tal vez de forma tan sencilla como una declaración que diga PRINT "I AM HERE"
), o pueden proporcionarse como herramientas. A menudo resulta sorprendente descubrir dónde se dedica la mayor parte del tiempo a un fragmento de código, y esta eliminación de suposiciones puede hacer que se reescriba el código.
El desarrollo de código abierto permite que cualquiera pueda examinar el código fuente. Una escuela de pensamiento popularizada por Eric S. Raymond como la ley de Linus dice que el software de código abierto popular tiene más posibilidades de tener pocos o ningún error que otro software, porque "si se le dan suficientes ojos, todos los errores son superficiales". [13] Sin embargo, esta afirmación ha sido cuestionada: el especialista en seguridad informática Elias Levy escribió que "es fácil ocultar vulnerabilidades en código fuente complejo, poco comprendido y no documentado", porque "incluso si la gente está revisando el código, eso no significa que estén calificados para hacerlo". [14] Un ejemplo de un error de software de código abierto fue la vulnerabilidad OpenSSL de 2008 en Debian .
La depuración puede ser una parte importante del ciclo de vida del desarrollo de software . Maurice Wilkes , uno de los pioneros de la informática, describió su descubrimiento a finales de la década de 1940 de que “gran parte del resto de mi vida la iba a pasar buscando errores en mis propios programas”. [15]
Un programa conocido como depurador puede ayudar a un programador a encontrar código defectuoso examinando el funcionamiento interno de un programa, como ejecutar el código línea por línea y visualizar los valores de las variables.
Como alternativa al uso de un depurador, el código puede instrumentarse con lógica para generar información de depuración con el fin de rastrear la ejecución del programa y visualizar los valores. La salida suele ser a una consola , una ventana , un archivo de registro o una salida de hardware (es decir, un LED ).
Algunos sostienen que localizar un error es todo un arte.
No es raro que un error en una sección de un programa provoque fallos en otra sección, [ cita requerida ] lo que dificulta su seguimiento, en una parte aparentemente no relacionada del sistema. Por ejemplo, un error en una rutina de representación de gráficos que provoque un error en una rutina de entrada/salida de archivos.
A veces, la parte más difícil de la depuración es encontrar la causa del error. Una vez encontrada, corregir el problema a veces es fácil, por no decir trivial.
A veces, un error no es un defecto aislado, sino que representa un error de pensamiento o planificación por parte de los programadores. A menudo, un error lógico de este tipo requiere que se revise o reescriba una sección del programa.
Algunos sostienen que, como parte de la revisión del código , recorrerlo e imaginar o transcribir el proceso de ejecución a menudo puede encontrar errores sin llegar a reproducir el error como tal.
Por lo general, el primer paso para localizar un error es reproducirlo de forma fiable. Si no se puede reproducir el problema, un programador no puede encontrar la causa del error y, por lo tanto, no puede solucionarlo.
Algunos errores se revelan mediante entradas que pueden resultar difíciles de recrear para el programador. Una de las causas de las muertes de la máquina de radiación Therac-25 fue un error (específicamente, una condición de carrera ) que se produjo solo cuando el operador de la máquina introdujo muy rápidamente un plan de tratamiento; se necesitaron días de práctica para poder hacer esto, por lo que el error no se manifestó en las pruebas o cuando el fabricante intentó duplicarlo. Otros errores pueden dejar de ocurrir siempre que se amplíe la configuración para ayudar a encontrar el error, como ejecutar el programa con un depurador; estos se denominan errores de Heisen (nombre humorístico que hace referencia al principio de incertidumbre de Heisenberg ).
Desde la década de 1990, en particular después del desastre del vuelo 501 del Ariane 5 , aumentó el interés en las ayudas automatizadas para la depuración, como el análisis de código estático mediante interpretación abstracta . [16]
A menudo, los errores surgen durante la codificación, pero una documentación de diseño defectuosa puede provocar un error. En algunos casos, los cambios en el código pueden eliminar el problema aunque el código ya no coincida con la documentación.
En un sistema integrado , el software a menudo se modifica para solucionar un error de hardware, ya que es más económico que modificar el hardware.
Los errores se gestionan mediante actividades como documentar, categorizar, asignar, reproducir, corregir y publicar el código corregido.
A menudo se utilizan herramientas para rastrear errores y otros problemas con el software. Por lo general, el equipo de desarrollo de software utiliza herramientas diferentes para rastrear su carga de trabajo que el servicio de atención al cliente para rastrear los comentarios de los usuarios . [17]
A un elemento rastreado se le suele llamar error , defecto , ticket , problema , característica o, en el caso del desarrollo ágil de software , historia o épica . Los elementos suelen clasificarse por aspectos como gravedad, prioridad y número de versión .
En un proceso que a veces se denomina triage , se toman decisiones para cada error sobre si se debe corregir y cuándo hacerlo en función de información como la gravedad y la prioridad del error y factores externos como los cronogramas de desarrollo. El triage generalmente no incluye la investigación de la causa. El triage puede realizarse con regularidad. El triage generalmente consiste en revisar los errores nuevos desde el triage anterior y tal vez todos los errores abiertos. Los asistentes pueden incluir al gerente de proyecto, al gerente de desarrollo, al gerente de pruebas, al gerente de compilación y a expertos técnicos. [18] [19]
La gravedad es una medida del impacto que tiene el error. [20] Este impacto puede ser pérdida de datos, financiera, pérdida de buena voluntad y esfuerzo desperdiciado. Los niveles de gravedad no están estandarizados, sino que difieren según el contexto, como la industria y la herramienta de seguimiento. Por ejemplo, una falla en un videojuego tiene un impacto diferente a una falla en un servidor bancario. Los niveles de gravedad pueden ser falla o bloqueo , sin solución alternativa (el usuario no puede realizar una tarea), tiene solución alternativa (el usuario aún puede realizar la tarea), defecto visual (un error ortográfico, por ejemplo) o error de documentación . Otro ejemplo de conjunto de gravedades: crítico , alto , bajo , bloqueador , trivial . [21] La gravedad de un error puede ser una categoría separada de su prioridad de reparación, o las dos pueden cuantificarse y gestionarse por separado.
Un error lo suficientemente grave como para retrasar el lanzamiento del producto se denomina " show stopper" . [22] [23]
La prioridad describe la importancia de resolver el error en relación con otros errores. Las prioridades pueden ser numéricas, como del 1 al 5, o con nombre, como crítico , alto , bajo y diferido . Los valores pueden ser similares o idénticos a las clasificaciones de gravedad, aunque la prioridad sea un aspecto diferente.
La prioridad puede ser una combinación de la gravedad del error y el nivel de esfuerzo necesario para solucionarlo. Un error de baja gravedad pero fácil de solucionar puede tener mayor prioridad que un error de gravedad moderada que requiera mucho más esfuerzo para solucionarlo.
Los errores que tienen una prioridad suficientemente alta pueden justificar un lanzamiento especial, a veces denominado parche .
Una versión de software que enfatiza la corrección de errores puede denominarse versión de mantenimiento , para diferenciarla de una versión que enfatiza nuevas características u otros cambios.
Es una práctica habitual lanzar software con errores conocidos y de baja prioridad u otros problemas. Las posibles razones incluyen, entre otras:
La cantidad y el tipo de daño que un error de software puede causar afecta la toma de decisiones, los procesos y las políticas en materia de calidad del software. En aplicaciones como los vuelos espaciales tripulados , la aviación , la energía nuclear , la atención sanitaria , el transporte público o la seguridad automotriz , dado que los fallos de software tienen el potencial de causar lesiones o incluso la muerte a personas, dicho software tendrá un escrutinio y un control de calidad mucho mayores que, por ejemplo, un sitio web de compras en línea. En aplicaciones como la banca, donde los fallos de software tienen el potencial de causar graves daños financieros a un banco o a sus clientes, el control de calidad también es más importante que, por ejemplo, en una aplicación de edición de fotografías.
Además del daño que causan los errores, parte de su costo se debe al esfuerzo invertido en corregirlos. En 1978, Lientz et al. demostraron que la media de los proyectos invierte el 17 por ciento del esfuerzo de desarrollo en la corrección de errores. [26] En 2020, una investigación sobre los repositorios de GitHub mostró que la media es del 20 %. [27]
En 1994, el Centro de Vuelo Espacial Goddard de la NASA logró reducir su número promedio de errores de 4,5 por 1000 líneas de código ( SLOC ) a 1 por 1000 SLOC. [28]
Otro estudio de 1990 informó que los procesos de desarrollo de software excepcionalmente buenos pueden lograr tasas de fallas de implementación tan bajas como 0,1 por 1000 SLOC. [29] Esta cifra se repite en la literatura como Code Complete de Steve McConnell , [30] y el estudio de la NASA sobre la complejidad del software de vuelo . [31] Algunos proyectos incluso alcanzaron cero defectos: el firmware de la máquina de escribir IBM Wheelwriter , que consta de 63 000 SLOC, y el software del transbordador espacial con 500 000 SLOC. [29]
Para facilitar la investigación reproducible sobre pruebas y depuración, los investigadores utilizan puntos de referencia seleccionados de errores:
Algunos tipos de errores notables:
Un error puede deberse a un diseño insuficiente o incorrecto según la especificación. Por ejemplo, dado que la especificación consiste en ordenar alfabéticamente una lista de palabras, puede producirse un error de diseño si el diseño no tiene en cuenta los símbolos, lo que daría como resultado una ordenación alfabética incorrecta de palabras con símbolos.
Las operaciones numéricas pueden generar resultados inesperados, procesamiento lento o fallas. [34] Un error de este tipo puede deberse a una falta de conocimiento de las cualidades del almacenamiento de datos, como una pérdida de precisión debido al redondeo , algoritmos numéricamente inestables , desbordamiento y subdesbordamiento aritmético , o por falta de conocimiento de cómo se manejan los cálculos mediante diferentes lenguajes de codificación de software, como la división por cero , que en algunos lenguajes puede generar una excepción y en otros puede devolver un valor especial como NaN o infinito .
Un error de flujo de control , también conocido como error lógico, se caracteriza por un código que no falla con un error, pero no tiene el comportamiento esperado, como un bucle infinito , una recursión infinita , una comparación incorrecta en un condicional como usar el operador de comparación incorrecto y el error de un dígito .
En agosto de 2016, el Open Technology Institute, dirigido por el grupo New America , [39] publicó un informe titulado "Bugs in the System" (Errores en el sistema), en el que se afirma que los responsables de las políticas estadounidenses deberían realizar reformas para ayudar a los investigadores a identificar y abordar los errores de software. El informe "destaca la necesidad de reformas en el campo del descubrimiento y la divulgación de vulnerabilidades de software". [40] Uno de los autores del informe dijo que el Congreso no ha hecho lo suficiente para abordar la vulnerabilidad del software cibernético, a pesar de que el Congreso ha aprobado una serie de proyectos de ley para combatir el problema más amplio de la ciberseguridad. [40]
Los investigadores gubernamentales, las empresas y los expertos en seguridad cibernética son quienes suelen descubrir los fallos de software. El informe pide reformar las leyes sobre delitos informáticos y derechos de autor. [40]
La Ley de Abuso y Fraude Informático, la Ley de Derechos de Autor del Milenio Digital y la Ley de Privacidad de las Comunicaciones Electrónicas penalizan y crean sanciones civiles para acciones que los investigadores de seguridad realizan rutinariamente mientras realizan investigaciones de seguridad legítimas, señala el informe. [40]
(Cobb y Mills 1990)