¿Cómo crear software de misión crítica?


15

Estoy aprendiendo métodos formales. Escuché que se usan métodos formales (y generalmente solo se usan) para crear software de misión crítica (como el controlador del reactor nuclear, el controlador de vuelo de la aeronave, el controlador de la sonda espacial). Por eso me interesa aprenderlo: p

Sin embargo, después de aprender métodos formales (especialmente LTL, CTL y sus hermanos), creo que solo pueden usarse para verificar la exactitud de la especificación (seguridad, vida, equidad, etc.).

Pero, ¿cómo verificar que el software (no solo la especificación) es correcto?

Descargo de responsabilidad: soy un 90% idiota cuando se trata de informática teórica. Así que por favor sé misericordioso mientras respondes.


2
¿Qué quiere decir exactamente con "... que el software es correcto ..." ? ¿Cuál de los siguientes 2 quiere decir: 1) El software cumple con la especificación 2) Los bloques específicos de código respetan alguna propiedad dada o alguna relación de entrada-salida.
Giorgio Camerani

@GiorgioCamerani: El primero
fajrian el

2
La corrección de un programa generalmente significa que (1) es consistente con una especificación y (2) nunca se bloquea. El punto (1) es realmente una declaración sobre el par (programa, especificación) más que sobre el programa en sí mismo. Otra complicación es que "programa" suele ser una abreviatura de "modelo de programa", porque los programas en sí mismos son bastante complicados o no tienen una semántica precisa. Dado esto, creo que está preguntando acerca de la brecha entre un programa y su modelo, pero no estoy muy seguro.
Radu GRIGore

@RaduGRIGore: En realidad no entiendo qué es "modelo". Pero creo que aborda mi pregunta muy de cerca. Básicamente, lo que me pregunto es la brecha entre la especificación y el código fuente del programa. Pueden suceder muchas cosas estúpidas cuando los programadores (como yo) están implementando la especificación.
fajrian

1
@fajrian: Sospecho que dices 'especificación' para lo que yo llamaría 'modelo'. Existen herramientas que funcionan en programas escritos en lenguajes como C o Java, o incluso en código de máquina. (Sigue siendo un modelo, sin embargo, ya que tienen que asumir alguna semántica, que deberían , pero no pueden, corresponden a lo que hace el compilador / procesador.)
Radu GRIGORE

Respuestas:


11

La pregunta es bastante amplia. Para responderlo en un espacio razonable haré muchas simplificaciones excesivas.

Acordemos la terminología. Un programa es correcto cuando implica su especificación. Esta declaración vaga se hace precisa de muchas maneras, al precisar qué es exactamente un programa y qué es exactamente una especificación. Por ejemplo, en la verificación de modelos, el programa es una estructura de Kripke y la especificación es a menudo una fórmula LTL . O bien, el programa podría ser una lista de instrucciones de PowerPC y la especificación podría ser un conjunto de afirmaciones de Hoare-Floyd escritas, digamos, en lógica de primer orden. Hay muchas variaciones posibles. Es tentador concluir que en un caso (estructura de Kripke) no verificamos un programa real, mientras que en el segundo caso (lista de instrucciones de PowerPC) lo hacemos. Sin embargo, es importante darse cuenta de que realmente estamos mirando modelos matemáticos en ambos casos, y esto está perfectamente bien. (La situación es bastante similar a la física donde, por ejemplo, la mecánica clásica es un modelo matemático de la realidad).

La mayoría de las formalizaciones distinguen entre la sintaxis y la semántica de un programa; es decir, cómo se representa y qué significa. La semántica de un programa es lo que cuenta desde el punto de vista de la verificación del programa. Pero, por supuesto, es importante tener una forma clara de asignar significados a (representaciones sintácticas de) programas. Dos formas populares son las siguientes:

  • (pequeño paso) semántica operativa : esto es muy parecido a definir un lenguaje de programación escribiendo un intérprete para él. Para esto, necesita decir cuál es el estado , y se ve afectado por cada declaración en el idioma. (Quizás se pregunte en qué idioma escribe al intérprete, pero fingiré que no lo está).
  • Semántica axiomática : aquí cada tipo de declaración viene con un esquema de axioma. Entonces, aproximadamente, cada vez que se usa una declaración particular de ese tipo, se traduce en poder usar ciertos axiomas. Por ejemplo, la asignación viene con el esquema { P [ x / e ] }X: =mi ; la asignación particular x : = x + 1 viene con el axioma { x + 1 = 1 }{PAG[X/ /mi]}X: =mi{PAG}X: =X+1 si instanciamos el esquema con P = ( x = 1 ) .{x+1=1}x:=x+1{x=1}P=(x=1)

(Hay otros. Me siento particularmente mal por omitir la semántica denotativa, pero esta respuesta ya es larga.) El código de máquina más la semántica operativa está bastante cerca de lo que la mayoría de la gente llamaría un "programa real". Aquí hay un documento seminal, que utiliza la semántica operativa para un subconjunto del código de máquina DEC Alpha:

¿Por qué usarías alguna semántica de nivel superior, como las axiomáticas? Cuando no desea que su prueba de corrección dependa del hardware en el que se ejecuta. El enfoque es demostrar la corrección de un algoritmo con respecto a alguna semántica conveniente de alto nivel, y luego probar que la semántica suena con respecto a la semántica de nivel inferior que está más cerca de las máquinas reales.

En resumen, podría pensar en tres razones que llevaron a su pregunta:

  1. Viste solo semánticas de alto nivel que no se parecen a lo que estás acostumbrado a llamar un programa, y ​​te preguntas si hay otras de bajo nivel. La respuesta es sí.
  2. Te preguntas cómo pruebas que un modelo corresponde a la realidad. Como en física, no lo haces. Simplemente tienes mejores modelos y los comparas con la realidad.
  3. No ha visto la distinción entre sintaxis y semántica, y varias formas de asignar significados a los programas. Dos preguntas anteriores enumeran algunos libros.

Esta respuesta simplemente trata de identificar tres formas diferentes en que entendí la pregunta. Profundizar en cualquiera de estos puntos requeriría mucho espacio.


8

Un enfoque para reducir la brecha entre un programa y su especificación es utilizar un lenguaje con una semántica formal. Un ejemplo interesante aquí sería Esterel . Eche un vistazo a la página web de Gérard Berry para ver algunas charlas interesantes sobre su trabajo de llevar métodos formales al mundo real. http://www-sop.inria.fr/members/Gerard.Berry/

ps ¿Has estado en un Airbus? ¡Has volado con métodos formales!


1
cualquier referencia sobre cómo Airbus utiliza métodos formales sería útil (entiendo que es posible información patentada)
vzn

@RossDuncan Encontré esta página web después de ir a la página web de Berry y algunas búsquedas. ¿Es este el método formal que Airbus estaba utilizando al que te referías?
scaaahu

No tengo ninguna información privilegiada sobre el uso de Esterel por Airbus; mi comentario simplemente repite un comentario que Berry hizo durante una conferencia. Sin embargo, esta página anuncia el uso exitoso del producto SCADE con Airbus. Si nos fijamos en la historia de Esterel, Dassault lo adoptó bastante pronto. Google es tu amigo.
Ross Duncan

2
Airbus también usa astree.ens.fr
Radu GRIGore

7

La ciencia de la construcción de software confiable en el "mundo real" todavía se está desarrollando y está en cierta medida al borde de un estudio inherentemente cultural o antropológico, porque las computadoras y el software no "causan" errores, ¡los humanos sí! Esta respuesta se centrará en los enfoques generales de preguntas y respuestas, de los cuales la verificación formal del software puede verse como un elemento.

Una observación notable es que a menudo el software que es "suficientemente bueno" pero "defectuoso" con frecuencia puede vender más que el software mejor probado pero de menor funcionalidad en el mercado. en otras palabras, el mercado no siempre otorga una importancia superior a la calidad del software y las técnicas modernas de ingeniería de software, que no siempre enfatizan la calidad, sino que reflejan eso. Además, la calidad a menudo puede agregar un gasto significativo al producto final. con esas advertencias, estos son algunos de los conceptos básicos:

  • Sistemas redundantes / tolerantes a fallas. Esta es un área amplia de estudio. La tolerancia a fallos y la redundancia se pueden diseñar en las muchas capas de un sistema. por ejemplo, un enrutador, un servidor, una unidad de disco, etc.

  • las pruebas . todos los tipos: pruebas unitarias, pruebas de integración, pruebas de aceptación del usuario, pruebas de regresión, etc.

  • Hoy en día, las pruebas automatizadas a través de conjuntos de pruebas que se pueden ejecutar sin supervisión son más desarrolladas / importantes. Las suites de prueba en ejecución a menudo se combinan con la herramienta de compilación.

  • Un concepto importante en las pruebas es la cobertura del código . es decir, qué código ejerce la prueba. una prueba no puede encontrar un error en el código que no haya sido "tocado" por la prueba.

  • Otro concepto clave en las pruebas es probar el arnés que ejercita el código al que no se puede acceder fácilmente directamente.

  • Las pruebas deben ejercitar todos los niveles del software. Si el software está bien modularizado, esto no es difícil. Las pruebas de nivel superior deben penetrar profundamente en el código. Las pruebas que ejercen grandes cantidades de código con una configuración de prueba pequeña aumentan el "apalancamiento de prueba" .

  • hacer que el código sea ​​lo menos complicado posible es importante para las pruebas. Las pruebas deben ser una consideración en el diseño de la arquitectura. a menudo hay varias formas de implementar la misma función, pero algunas tienen implicaciones muy diferentes para la cobertura / apalancamiento de la prueba. para cada rama en el código, a menudo es otro caso de prueba. las ramas dentro de las ramas aumentan exponencialmente en las rutas de código. por lo tanto, evitar la lógica altamente anidada / condicional mejora la capacidad de prueba.

  • estudiar fallas de software famosas (masivas) de las cuales hay muchos ejemplos y estudios de casos es útil para comprender la historia y desarrollar una mentalidad orientada hacia consideraciones de calidad.

  • ¡uno puede dejarse llevar por las pruebas! Existe un problema con muy poca o demasiada prueba. hay un "punto dulce". el software no se puede construir con éxito en ninguno de los extremos.

  • use todas las herramientas básicas de la manera más efectiva. depuradores, perfiladores de código, herramientas de cobertura de código de prueba, sistema de seguimiento de defectos, etc. no necesariamente se compromete a arreglar, pero rastrea incluso los defectos más pequeños en el software de seguimiento.

  • El uso cuidadoso de SCM, la gestión del código fuente y las técnicas de ramificación es importante para evitar regresiones, aislar y progresar soluciones, etc.

  • Programación en versión N : una práctica utilizada a menudo para desarrollar software de misión crítica. La premisa de esta práctica es que es poco probable que N programas desarrollados independientemente tengan el mismo error / falla común. Esto ha sido criticado en algunos artículos . NVP es, sin embargo, una práctica, no un concepto teórico.

Creo que el físico Feynman tiene una explicación del método que utilizó la NASA para garantizar la confiabilidad de los sistemas de transbordadores espaciales en su libro "¿Qué le importa lo que piensen los demás?" - Dijo que tenían dos equipos, digamos el Equipo A y el Equipo B. El equipo A construyó el software. El equipo B adoptó un enfoque de confrontación con el equipo A e intentó romper el software.

ayuda si el Equipo B tiene buenos antecedentes en ingeniería de software, es decir, ellos mismos pueden escribir arneses de código / pruebas programáticas, etc. en ese caso, el Equipo B tenía casi el mismo nivel de recursos que el Equipo A. Por otro lado, este enfoque es costoso porque casi puede duplicar el costo de construir el software. más típicamente, hay un equipo de control de calidad más pequeño en comparación con el equipo de desarrollo.


8
Alguien debe verificar que su sistema operativo sea correcto con respecto a la especificación de que presionar la tecla Mayús y una letra produce una letra mayúscula.
Andrej Bauer

1
Anexo: las restricciones de programación pueden afectar la calidad. vea también el triángulo de gestión de proyectos compuesto por alcance, costo, cronograma con calidad del "área" afectada por todos 3. vea también "¿Por qué la industria de TI no puede entregar proyectos grandes e impecables tan rápido como en otras industrias?" . Yo mismo no agregué el elemento de la versión N [está cubierto por otra respuesta] pero tenga en cuenta que Feynman mencionó que la NASA también lo usó en el diseño del transbordador espacial.
vzn


1
Otro caso de estudio interesante es el Mars Rover, que tiene grandes cantidades de código, en gran parte autogenerado. en ese caso, los rovers anteriores probaron la mayor parte del software y se reutilizó.
vzn

6

Un enfoque antiguo (pero todavía se usa en algunas aplicaciones) es la programación de la versión N

De Wikipedia:

La programación de la versión N ( NVP ), también conocida como programación multiversion , es un método o proceso en la ingeniería de software donde se generan múltiples programas funcionalmente equivalentes independientemente de las mismas especificaciones iniciales. El concepto de programación de la versión N fue introducido en 1977 por Liming Chen y Algirdas Avizienis con la conjetura central de que "la independencia de los esfuerzos de programación reducirá en gran medida la probabilidad de que ocurran fallas de software idénticas en dos o más versiones del programa". de NVP es mejorar la confiabilidad de la operación del software incorporando tolerancia a fallas o redundancia.
....

Ver por ejemplo: " Desafíos en la construcción de fallas - Sistema de control de vuelo tolerante para una aeronave civil "


Vale la pena señalar que la programación de la versión n no funciona . La suposición fundamental, es decir, que los errores en las pruebas repetidas del proceso de desarrollo de software son independientes, es completamente falsa . Esta idea no tiene sentido teóricamente (un algoritmo difícil de implementar no será mágicamente más fácil para un segundo equipo independiente), y también ha sido desacreditado experimentalmente: el experimento de John Knight y Nancy Leveson que muestra que el supuesto de independencia no es estadísticamente válido Es uno de los trabajos más famosos en ingeniería de software.
Neel Krishnaswami

@NeelKrishnaswami: ¡Estoy de acuerdo! Sin embargo, creo que (pero no soy un experto) que no funciona debería reemplazarse con él, no mejora la fiabilidad tanto como debería si se compara con otros enfoques . Citando K&L: " ... Nunca sugerimos que nuestro resultado debería ser usado por nosotros mismos como base para una decisión sobre la efectividad de la programación de la versión N. Simplemente sugerimos que la precaución sería apropiada ... ". Creo que el debate sobre cuánto puede ser útil el enfoque de NVP para el diseño de sistemas críticos aún está abierto (ver el trabajo reciente de Khoury et al.)
Marzio De Biasi

4

Fajrian, esta pregunta que ha hecho cubre dos de los mayores problemas en la investigación del ingeniero de software: la conformidad entre la especificación y el modelo y entre el modelo y el código. Modele aquí una representación de lo que hará el sistema, o cómo se hará, hay muchos niveles para modelar un sistema.

Entonces, hay algunas personas que intentan encontrar la mejor respuesta a su pregunta. Debido a que es muy difícil verificar la corrección de un software basado en un modelo, por ejemplo, utilizando métodos formales. Sé que JML es una forma de hacerlo, pero no conozco los límites de su uso.

Para concluir, cómo es difícil hacer la verificación de la corrección del código, las personas intentan mezclar métodos formales y pruebas, creando pruebas automáticamente a partir de especificaciones, por ejemplo. Un ejemplo para los sistemas en tiempo real son los TIOSTS que se basan en eventos temporizados de entrada / salida.

Probar solo no es un enfoque de método formal, hacerlo mejora la confiabilidad pero no verifica la corrección.


3

Hace dos o tres años comencé a analizar los métodos formales aplicados al software. Esta fue una búsqueda impulsada por la curiosidad y por la sensación de que tenía que aprender herramientas y métodos de programación con períodos de tiempo más largos. Aunque soñé con desear un Silver Bullet , realmente pensé que no había una respuesta a la pregunta: "¿Cómo puedo escribir un programa correcto?".

En este punto de la búsqueda después de probar algunas herramientas (Z, B, VHDL y Estelle), estoy usando TLA + . Esta es una variante de la lógica temporal con herramientas de software para la verificación de modelos y pruebas mecánicas. Creo que elegí este enfoque porque L. Lamport lo respaldaba, la sintaxis era simple, había muchos ejemplos, había una comunidad que se encargaba de ello y el lenguaje y las herramientas estaban bastante bien documentados.

Con respecto a mi pregunta inicial, creo que no hay una respuesta completa. Sin embargo, vale la pena aprender que vale la pena especificar formalmente algunas partes de un sistema. También es bastante útil realizar ingeniería inversa en algunos complejos. Es decir, es efectivo crear un plan para las partes difíciles y críticas. Sin embargo, no creo que haya un método efectivo para traducir automáticamente la especificación a un lenguaje o marco de programación (a menos que restrinja el proyecto a un entorno muy específico). Tampoco creo que tener una especificación formal deba impedir que pruebe el software.

En pocas palabras, creo que la siguiente metáfora (de Lamport) es realmente poderosa: "¿Esperas que una casa se construya automáticamente a partir de un plano? ¿Comprarás una casa que aún no está construida y no tiene un plano?" .

Durante esta búsqueda, he encontrado útiles los siguientes recursos:

¡Buena suerte!


1

Las respuestas hasta ahora cubrieron la mayor parte de lo que debería decirse sobre los fundamentos de cómo se relacionan la especificación y el código entre sí. Solo quiero agregar un punto más práctico que aborde la pregunta en el encabezado de este hilo:

¿Cómo crear software de misión crítica?

Existen herramientas que analizan automáticamente su código en busca de errores (violaciones de la especificación o "errores típicos"). Que yo sepa, estos métodos se basan principalmente en el análisis estático y no están inmediatamente relacionados con las teorías que mencionó (LTL / CTL / ...), pero sí encuentran errores en el código real y ya es factible, desde un punto de vista práctico. vista, para usar tales herramientas en proyectos industriales. Personalmente no he usado muchos de ellos, pero parece que estas herramientas comienzan a ser aceptadas por los profesionales. Para leer más, puedo recomendar el siguiente artículo de blog:

http://www.altdevblogaday.com/2011/12/24/static-code-analysis/


ejemplo de implementación con java, código abierto apache— findbugs
vzn

0

Los algoritmos de certificación pueden ser útiles al construir software de misión crítica.

Un algoritmo de certificación es un algoritmo que produce, con cada salida, un certi fi cado o testigo (prueba fácil de verificar) de que la salida en particular no ha sido comprometida por un error.

Lea más en este documento de encuesta Algoritmos de certificación de McConnell, RM y Mehlhorn, K. y Naher, S. y Schweitzer, P.


En 1998, Pnueli, Siegel y Singerman describieron esta idea aplicada a los compiladores, bajo la validación de traducción de nombres . Los compiladores son inherentemente de orden superior (la entrada es un programa, la salida es un programa), por lo que tienden a ser difíciles de verificar. Pero hay personas locas como X. Leroy que desarrollan compiladores verificados de todos modos. (¡Loco en el mejor sentido posible!)
Radu GRIGore

-2

Pero, ¿cómo verificar que el software (no solo la especificación) es correcto?

¿Examen de la unidad? Escriba una prueba para cada requisito en la especificación y luego pruebe cada método en su implementación para ver que su salida / entrada se ajusta a dicha especificación. Esto se puede automatizar para que estas pruebas se ejecuten continuamente para garantizar que ningún cambio rompa nunca las funciones que funcionaban anteriormente.

Teóricamente hablando, si las pruebas de su unidad tienen una cobertura del código del 100% (es decir, se prueba cada método en su código) su software debe ser correcto, siempre que las pruebas en sí sean precisas y realistas.


55
Para cualquier programa razonablemente complejo, la cobertura del código (mediante pruebas) no puede garantizar la corrección. Tendría que cubrir todas las ejecuciones posibles; Todas las líneas de código no son suficientes.
Radu GRIGore

1
La cobertura del código es un concepto demasiado vago. Distinguimos entre, por ejemplo, cobertura de método, cobertura de estado de cuenta, cobertura de sucursal, cobertura de ruta, etc. Como señala Radu, para los programas no triviales, las pruebas a menudo se topan con explosiones combinatorales. Dicho esto, el software aeronáutico tiene un historial bastante bueno, y su corrección a menudo se basa en pruebas exhaustivas.
Martin Berger

Si te refieres a probar con herramientas como JUnit, este tipo de prueba automática estándar no puede cubrir todos los casos (a menos que el programa sea extremadamente pequeño). Para una aplicación típica, este tipo de prueba suele ser suficiente. Pero para la aplicación de misión crítica, no sé si esto es suficiente (o no).
fajrian

2
@vzn: En mi experiencia, existe un acuerdo notable entre lo que los académicos y los profesionales, respectivamente, consideran un error. Además, apuesto a que la mayoría de mis (antiguos) colegas de la industria estarían de acuerdo en que "cada método en su código se prueba" no suena muy tranquilizador. (Y no, no voté en contra. Casi nunca lo hago.)
Radu GRIGore

1
@vzn: ¿Dije que dijiste lo contrario? Simplemente estaba tratando de explicar por qué creo que otros no están votando esta respuesta. En este momento no puedo responder a esta pregunta, porque no la entiendo.
Radu GRIGore
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.