OpenCyber Academy
Grado · Capítulo 8 · Español
Código del curso: OCA-114Capítulo 08: OCA-114-C008

Capítulo 8 — Programación II

Aprendizaje gratuito y abierto para quienes desean proteger a las personas y la tecnología. No se necesita una cuenta para estudiar ni consultar las respuestas.

Mapa de la lección

Lección 08 publicada. Mapa, ejemplo, EX022.

flowchart TD
  N0["Resultados de aprendizaje"]
  N1["8.1 Las funciones puras se pueden revisar"]
  N2["8.2 Fallar de forma cerrada"]
  N3["8.3 Las pruebas como documentación"]
  N4["8.4 Registrar las decisiones para revisarlas"]
  N5["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5
  N5 --> EX["Ejemplo resuelto"]
  EX --> Q["Ejercicio EX022"]

Dibujo lógico

flowchart LR
  N0["Resultados de aprendizaje"]
  N1["8.1 Las funciones puras se pueden revisar"]
  N2["8.2 Fallar de forma cerrada"]
  N3["8.3 Las pruebas como documentación"]
  N4["8.4 Registrar las decisiones para revisarlas"]
  N5["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX022"]
[Resultados de aprendizaje]
    |
    v
[8.1 Las funciones puras se pueden revisar]
    |
    v
[8.2 Fallar de forma cerrada]
    |
    v
[8.3 Las pruebas como documentación]
    |
    v
[8.4 Registrar las decisiones para revisarlas]
    |
    v
[Síntesis del capítulo]
    |
    v
[Ejemplo resuelto] --> [Ejercicio EX022]

Resultados de aprendizaje

Usted podrá (1) estructurar una herramienta de análisis como funciones puras con pruebas; (2) usar unittest de la biblioteca estándar; (3) hacer que las funciones fallen de forma cerrada; y (4) versionar un script para que un resultado pueda reproducirse meses después.

8.1 Las funciones puras se pueden revisar

Una función que recibe entradas y devuelve una decisión, sin leer la red ni el reloj, puede probarse de forma exhaustiva. En las herramientas de TO esto importa porque el revisor suele ser un ingeniero de control que solo aceptará una herramienta si se demuestra su comportamiento en los casos límite. Mantenga la entrada y la salida (archivos, impresión) en los bordes y la lógica de decisión en el centro. El clasificador de Maya está escrito así: classify(code) recibe un código de función y devuelve una palabra, de modo que un ingeniero de control puede leer la lista de pruebas y ver cada decisión sin ejecutar una captura.

8.2 Fallar de forma cerrada

Cuando una función de lista de permitidos recibe un origen desconocido, un código de función desconocido o una dirección mal formada, debería devolver «bloquear» en lugar de lanzar una excepción que quien la llama podría capturar e ignorar. Fallar de forma cerrada significa «marcar para revisión» en una herramienta de supervisión y «denegar» en un dispositivo de aplicación. Ninguno de los dos significa «suponer que está bien». El primer clasificador de Maya fallaba de forma abierta: todo lo que estaba fuera del conjunto de escrituras devolvía «read». Un revisor preguntó por el código 8, diagnóstico, cuyas subfunciones pueden reiniciar las comunicaciones, y la respuesta dejó al descubierto el fallo. Su corrección devuelve «unknown», que en un monitor sin conexión significa marcar para revisión.

8.3 Las pruebas como documentación

Una pequeña lista de casos de unittest se lee como una especificación:

import unittest
def classify(fc):
    return "write" if fc in (5, 6, 15, 16) else ("read" if fc in (1, 2, 3, 4) else "unknown")
class T(unittest.TestCase):
    def test_codes(self):
        self.assertEqual(classify(3), "read"); self.assertEqual(classify(16), "write")
        self.assertEqual(classify(8), "unknown"); self.assertEqual(classify(43), "unknown")
unittest.main(argv=["x"], exit=False)

Al ejecutarla se imprime Ran 1 test y OK. El código 43 (transporte de interfaz encapsulada, usado para identificar dispositivos) es deliberadamente «unknown» en lugar de «read», porque el autor de la herramienta no ha razonado sobre él.

La lista de pruebas es también la especificación que firma un revisor: classify(3) es lectura, classify(16) es escritura, classify(8) y classify(43) son desconocidos. El fallo original de Maya lo habría detectado una sola aserción de que el código 8 devuelve «unknown»; esa aserción está ahora en la lista. Cuando aparece un nuevo código de función en una captura de LDHP, el primer cambio es una nueva aserción con la respuesta esperada, escrita antes de modificar el clasificador.

Ejemplo resuelto (LDHP sintética)

El primer clasificador de Maya devolvía «read» para todo lo que no estaba en el conjunto de escrituras. Un revisor preguntó qué devolvería el código 8 (diagnóstico). La respuesta, «read», era incorrecta: algunas subfunciones de diagnóstico reinician las comunicaciones. Ella cambió el valor por defecto a «unknown» y añadió la prueba anterior.

Caso sintético — Lakeside District Heating Plant. El clasificador es una herramienta didáctica para capturas sin conexión, no un dispositivo de aplicación.

8.4 Registrar las decisiones para revisarlas

Cada decisión que toma la herramienta debería escribirse junto con la entrada que la produjo, la regla que se activó y la versión del script, por ejemplo fc=8 -> unknown (rule: default) v=3f2a91c. Un ingeniero de control que revise una semana de capturas puede entonces filtrar por «unknown» y decidir, caso por caso, si el clasificador necesita una regla nueva. Este registro es también lo que le permite demostrar más tarde que un resultado sorprendente provino de una versión conocida del código y no de una modificación hecha después.

Errores y límites

Las pruebas demuestran los casos que usted escribió, no los que olvidó. Registre la versión del script (un hash de commit de git) junto a cada resultado que publique.

Ejercicios — capítulo 8

Síntesis del capítulo

Las herramientas de TO revisables son puras, están probadas, fallan de forma cerrada y están versionadas: propiedades que permiten a un ingeniero escéptico confiar en su salida.

Siga estudiando — capítulo 08 de 40

← Capítulo 07 (borrador) · Índice de capítulos del curso · Capítulo 09 (borrador) →

Respuestas desarrolladas

EX022. «unknown». Las subfunciones de la función 8 incluyen reiniciar las comunicaciones o borrar contadores, así que etiquetarla como «read» subestimaría su efecto; «unknown» obliga a que una persona la revise.

EX023. self.assertEqual(classify(8), "unknown"): con el código original esto devolvía «read» y la prueba fallaría.

EX024. El hash de commit de git del script que produjo el resultado y un hash SHA-256 (más la fecha de captura) del archivo de entrada exacto; la versión de Python es un tercer elemento útil.