Tema 15 · Bloque E · Sistemas informáticos. Programación

Tema 15. Estructuras de datos y proceso de desarrollo

Cómo se guardan muchos datos en una sola variable y cómo se organiza, se comprueba y se corrige un programa que crece.

Con el Tema 14 el KR-1 ya mide y actúa. Lo que no sabe todavía es recordar. Este tema le da memoria: estructuras para guardar muchos datos, un archivo donde sobrevivan al apagón y unas gráficas que conviertan ocho mil números en una conclusión. Y cierra el bloque con lo que el currículo llama proceso de desarrollo: edición, interpretación, ejecución, pruebas y depuración, que es la destreza que más distingue a quien programa bien.

Antes de empezar: tienes cuatro lecturas y las guardas en cuatro variables: medida1, medida2, medida3, medida4. Funciona. Ahora tienes ocho mil. Esa imposibilidad es la razón de que existan las estructuras de datos, y también la razón de que exista el bucle for del tema anterior: las dos cosas van juntas.
Al terminar serás capaz de…
  • crear, recorrer, buscar y modificar listas, y usar sus operaciones habituales;
  • explicar qué aporta una tupla frente a una lista y cuándo conviene cada una;
  • usar diccionarios para representar los datos de un proyecto con claves con nombre;
  • tratar una cadena como secuencia: acceder, trocear y aplicar sus métodos;
  • elegir la estructura de datos adecuada a un problema técnico y justificarlo;
  • registrar una serie de medidas en un archivo CSV y volver a leerla;
  • representar gráficamente una serie y extraer de ella una conclusión;
  • describir el proceso de desarrollo completo y la diferencia entre compilar e interpretar;
  • clasificar un error, leer su traza y depurar paso a paso con puntos de interrupción.

1. Listas

Una lista es una colección ordenada de elementos, guardada en una sola variable. Es la estructura de datos que más se usa y, con diferencia, la primera que hay que dominar.

medidas = [420, 515, 380, 610]

print(medidas[0])      # 420   el primero es el índice 0
print(medidas[3])      # 610
print(medidas[-1])     # 610   el último, contando desde el final
print(medidas[-2])     # 380
print(len(medidas))    # 4     número de elementos
El primer elemento es el 0, y el último es el len − 1Con cuatro elementos, los índices válidos son 0, 1, 2 y 3. Escribir medidas[4] produce IndexError. Es el error de índice más frecuente y tiene el mismo origen que el range(5) del Tema 14: contar desde cero. El índice negativo -1 es el atajo para el último elemento y evita la mitad de esos errores.
Las operaciones que se usan de verdad
OperaciónQué haceEjemplo
lista.append(x)Añade x al final.medidas.append(590)
lista[i] = xSustituye el elemento i.medidas[0] = 425
lista.pop()Saca y devuelve el último.ultima = medidas.pop()
x in listaDevuelve True si x está.if 4095 in medidas:
lista.index(x)Posición de la primera aparición.medidas.index(610) → 3
len(), sum(), min(), max()Número, suma y extremos.sum(medidas) / len(medidas)
sorted(lista)Devuelve una copia ordenada.ordenadas = sorted(medidas)
lista[a:b]Trozo desde a hasta b sin incluirlo.medidas[1:3][515, 380]
# La media, ahora en una línea
medidas = [420, 515, 380, 610]
media = sum(medidas) / len(medidas)
print(f"Media: {media:.1f}")     # Media: 481.3

# Y la mediana, que resiste mejor un valor disparatado
ordenadas = sorted(medidas)
mitad = len(ordenadas) // 2
if len(ordenadas) % 2 == 1:
    mediana = ordenadas[mitad]
else:
    mediana = (ordenadas[mitad - 1] + ordenadas[mitad]) / 2
print(f"Mediana: {mediana:.1f}")   # Mediana: 467.5
Media o mediana: una decisión de ingenieríaSi una de las cuatro lecturas hubiera sido 4095 —sensor desconectado—, la media saltaría a 1352 y el programa creería que el sustrato está saturado. La mediana apenas se movería. En series de medidas reales, con ruido y fallos ocasionales, la mediana es más robusta que la media, y elegir una u otra no es una cuestión de estadística abstracta: es decidir cómo debe comportarse el sistema cuando un sensor falla.
Listas de listas para tablas. Una lista cuyos elementos son listas representa una tabla: tabla[fila][columna]. Sirve para guardar varias series a la vez —la humedad de tres bancales—, y es la estructura que aparecerá al leer un archivo CSV en la sección 6.

2. Tuplas

Una tupla es como una lista pero inmutable: una vez creada, no se puede modificar. Se escribe con paréntesis en lugar de corchetes.

calibracion = (3000, 1200)        # (seco, saturado)
seco, saturado = calibracion      # desempaquetado en dos variables
print(seco, saturado)             # 3000 1200

# calibracion[0] = 2900           # TypeError: no se puede modificar

def leer_sensor():
    """Devuelve varias cosas a la vez: en realidad, una tupla."""
    return 2847, 22.5, True       # cuentas, temperatura, valido

cuentas, temperatura, valido = leer_sensor()
Para qué sirve que no se pueda modificarDos cosas. 1. Seguridad: los datos de calibración, las coordenadas de un punto o los límites de un rango no deben cambiar por accidente a mitad del programa, y la tupla lo garantiza. 2. Devolver varios valores: una función que devuelve tres cosas devuelve en realidad una tupla, y al recibirla se desempaqueta en tres variables de un golpe. Es el uso más frecuente y ni siquiera hay que pensar en él.

3. Diccionarios

Un diccionario guarda pares de clave y valor. En lugar de acceder por posición, se accede por un nombre, y eso cambia por completo la legibilidad de un programa de proyecto.

lectura = {
    "instante": "2027-07-14 08:15",
    "humedad_pct": 8.5,
    "temperatura_c": 22.5,
    "valvula": False,
    "bancal": 2,
}

print(lectura["humedad_pct"])        # 8.5
lectura["valvula"] = True            # modificar
lectura["duracion_s"] = 30           # añadir una clave nueva

print(lectura.keys())                # las claves
print(lectura.get("caudal", 0))      # 0 si la clave no existe: no falla
Compara las dos formas de guardar una lecturaComo tupla: (“2027-07-14 08:15”, 8.5, 22.5, False, 2). Como diccionario: cada dato con su nombre. Con la tupla, seis meses después nadie sabrá si el 2 final es el bancal o el número de riegos, y bastará con intercambiar dos valores para que el programa siga funcionando y mienta. Con el diccionario, lectura["bancal"] se explica solo. En un proyecto, los datos se guardan con su nombre.
# Un diccionario también sirve como configuración del sistema
CONFIG = {
    "umbral_riego_pct": 30,
    "duracion_riego_s": 30,
    "hora_inicio": 7,
    "hora_fin": 10,
    "periodo_medida_s": 900,
}

if humedad < CONFIG["umbral_riego_pct"]:
    regar(CONFIG["duracion_riego_s"])
Y es el formato de los datos que viajan por la red. Los mensajes que el KR-1 publicará en el Tema 16 tienen exactamente esta forma: pares de clave y valor. El formato JSON que se usa en el internet de las cosas es, para lo que nos interesa, un diccionario escrito como texto. Por eso los diccionarios entran en este curso: no son un lujo, son el puente al Tema 16.

4. Cadenas como secuencias

Una cadena de texto es también una secuencia, y admite los índices y los troceados de una lista.

linea = "2027-07-14;08:15;2847;22.5"

print(linea[0])          # 2
print(linea[0:4])        # 2027     los cuatro primeros caracteres
print(len(linea))        # 26
print(linea.split(";"))  # ['2027-07-14', '08:15', '2847', '22.5']

campos = linea.split(";")
fecha = campos[0]
cuentas = int(campos[2])
temperatura = float(campos[3])
Los métodos de cadena que se usan en este curso
MétodoQué haceEjemplo
split(sep)Parte la cadena en una lista.Leer una línea de un CSV.
strip()Quita espacios y saltos de línea de los extremos.Limpiar lo que llega de un archivo.
replace(a, b)Sustituye texto."2,5".replace(",", ".") antes de convertir.
join(lista)Une una lista de cadenas con un separador.";".join(campos) para escribir un CSV.
upper(), lower()Cambia a mayúsculas o minúsculas.Comparar sin depender de las mayúsculas.
startswith(x)Comprueba si empieza por algo.Saltar la línea de cabecera de un archivo.
strip() y replace() resuelven los dos problemas de todo dato que viene de fuera: el salto de línea invisible al final —que hace fallar a int() sin que se vea por qué— y la coma decimal española, que Python no acepta. El Tema 13 avisaba de que todo dato externo hay que convertirlo; estos dos métodos son la limpieza previa a esa conversión.

5. Elegir la estructura de datos

Qué estructura para qué problema
Necesito…EstructuraEjemplo en el KR-1
Muchos valores del mismo tipo, en orden, que crecen.ListaLas lecturas del día para promediar.
Un conjunto fijo de valores que no debe cambiar.TuplaLos dos puntos de calibración.
Devolver varias cosas de una función.Tuplareturn cuentas, temperatura, valido
Datos heterogéneos, cada uno con su nombre.DiccionarioUna lectura completa, o la configuración del sistema.
Texto que hay que partir o limpiar.Cadena y sus métodosUna línea leída del archivo de registro.
Una tabla de filas y columnas.Lista de listas, o lista de diccionariosEl histórico completo del verano.
La regla prácticaMuchos datos iguales → lista. Datos distintos con nombre → diccionario. Datos que no deben cambiar → tupla. Y para un histórico, lo mejor de los dos mundos: una lista de diccionarios, donde cada elemento es una lectura completa con sus claves. Es exactamente la forma que tendrá el archivo de la sección siguiente.

6. Series de medidas y ficheros CSV

Una lista vive en la memoria y desaparece al apagar. Para que las ocho mil lecturas del verano sobrevivan hay que escribirlas en un archivo, y el formato es el CSV: texto plano, una fila por línea y los campos separados por un carácter. Lo abre cualquier hoja de cálculo y lo lee cualquier lenguaje.

# Escribir el registro: en la placa y en el ordenador funciona igual
def registrar(instante, cuentas, humedad_pct, rego):
    """Añade una línea al archivo de registro."""
    with open("registro.csv", "a") as f:
        f.write(f"{instante};{cuentas};{humedad_pct:.1f};{int(rego)}\n")

registrar("2027-07-14 08:15", 2847, 8.5, True)
with open(...) y el modo de aperturaLa forma with garantiza que el archivo se cierra aunque el programa falle a mitad, y eso evita perder datos. Los modos importan: "a" añade al final —lo que quiere un registro—, "w" borra el contenido anterior y empieza de cero, y "r" solo lee. Confundir "a" con "w" es el error que borra el registro de todo el verano en una ejecución.
# Leer el registro y convertirlo en una lista de diccionarios
def cargar_registro(ruta="registro.csv"):
    lecturas = []
    with open(ruta, "r") as f:
        for linea in f:
            linea = linea.strip()
            if not linea or linea.startswith("#"):
                continue                      # salta vacías y comentarios
            campos = linea.split(";")
            if len(campos) != 4:
                continue                      # línea corrupta: la descarta
            lecturas.append({
                "instante": campos[0],
                "cuentas": int(campos[1]),
                "humedad_pct": float(campos[2]),
                "rego": campos[3] == "1",
            })
    return lecturas

datos = cargar_registro()
print(f"{len(datos)} lecturas cargadas")
Un archivo real siempre tiene líneas malas. La última línea puede estar a medio escribir porque se cortó la corriente; puede haber líneas vacías, o con un campo de menos. Un programa que dé por buenas todas las líneas se detendrá con un error el día que las necesites. Las dos comprobaciones del código —saltar vacías y descartar las que no tienen cuatro campos— son diez segundos de escritura y la diferencia entre un análisis que funciona en septiembre y uno que no.
# Y ahora la conclusión que pedía la pregunta guía
riegos = [d for d in datos if d["rego"]]
CAUDAL_L_H = 4.0          # litros por hora del gotero, del catálogo
DURACION_H = 30 / 3600    # 30 s expresados en horas

agua_usada = len(riegos) * CAUDAL_L_H * DURACION_H
print(f"Riegos: {len(riegos)}")
print(f"Agua consumida: {agua_usada:.1f} L")

7. Representar los datos

Ocho mil números no son una conclusión. Una gráfica sí, y en Jupyter Notebook se obtiene en cuatro líneas con la biblioteca matplotlib.

import matplotlib.pyplot as plt

humedades = [d["humedad_pct"] for d in datos]
UMBRAL_PCT = CONFIG["umbral_riego_pct"]

plt.plot(humedades)
plt.xlabel("Número de lectura")
plt.ylabel("Humedad (%)")
plt.title("Humedad del bancal 2, julio de 2027")
plt.axhline(UMBRAL_PCT, linestyle="--", label="umbral de riego")
plt.legend()
plt.grid(True)
plt.show()
Una gráfica técnica lleva siempre cuatro cosasTítulo que diga qué es y de cuándo; ejes rotulados con su unidad; escala razonable; y las referencias que permiten interpretarla —aquí, la línea del umbral—. Es el mismo rigor de la documentación técnica del Tema 4: una gráfica sin unidades en los ejes no es un resultado, es un dibujo. Y esta gráfica sí va en la memoria del proyecto.
La comprensión de lista. La expresión [d["humedad_pct"] for d in datos] construye una lista nueva recorriendo otra. Es una forma abreviada del bucle for con append del Tema 14, y se usa constantemente al tratar datos porque se lee casi como una frase: «la humedad de cada d en datos». No es imprescindible, y una vez vista resulta difícil volver atrás.
Piensa: la gráfica tiene el número de lectura en el eje horizontal, no la fecha. Con lecturas cada quince minutos es casi lo mismo… salvo los días que el sistema estuvo apagado, en los que el eje miente. ¿Cómo lo detectarías en la propia gráfica, y qué habría que cambiar para que no ocurriera?

8. El proceso de desarrollo

El currículo enumera las fases: edición, compilación o interpretación, ejecución, pruebas y depuración. Y añade una que no está en la lista y ocurre siempre: volver a empezar.

Edición

Escribir el código fuente en un editor. En Colab, las celdas del notebook; en Thonny, un archivo .py.

Interpretación o compilación

En Python, el intérprete lee y ejecuta. En C o C++, un compilador traduce todo antes y produce un ejecutable.

Ejecución

El programa corre con unos datos concretos. En la placa, además, hay que grabarlo antes.

Pruebas

Comprobar con los casos previstos —y con los que no—. Los assert del Tema 13 son pruebas que se ejecutan solas.

Depuración

Localizar y corregir la causa de un comportamiento incorrecto. Es la sección 10.

Y otra vuelta

Cada corrección es una iteración del Tema 1, y cada cambio relevante va al registro de cambios del Tema 4.

Compilar

Se traduce todo el programa a código máquina antes de ejecutar. Los errores de sintaxis aparecen de golpe al compilar; el ejecutable resultante es rapidísimo y no necesita el compilador para funcionar.

Interpretar

Se lee y ejecuta línea a línea. Los errores aparecen cuando la ejecución llega a ellos; se puede probar al instante, y hace falta el intérprete en la máquina que ejecute.

Una consecuencia práctica que conviene tener claraComo Python es interpretado, un error de escritura en una línea que no se ejecuta no se detecta. Si la rama else de tu programa tiene una errata y nunca se cumple esa condición durante las pruebas, el programa parecerá correcto hasta el día que se cumpla —en agosto, en el huerto, sin nadie delante—. De ahí la insistencia en los casos de prueba: en un lenguaje interpretado, lo que no se ejecuta no se comprueba.

9. Módulos y bibliotecas

Un módulo es un archivo con funciones reutilizables; una biblioteca, un conjunto de módulos. Python trae muchos incluidos —la biblioteca estándar— y se importan con import.

Los módulos que se usan en este curso
MóduloPara quéDónde
mathFunciones matemáticas, π, raíces, trigonometría.Cálculos de los bloques C, D y G.
timeEsperas y marcas de tiempo.Cadencia de medida y duración del riego.
statisticsMedia, mediana y desviación típica.Tratamiento de series de medidas.
csvLectura y escritura robusta de CSV.Alternativa a hacerlo a mano, en el ordenador.
matplotlibGráficas.Memoria del proyecto.
machinePines, ADC y PWM de la placa.Solo en MicroPython, temas 14 a 19.
network, umqttWi-Fi y mensajería.Solo en MicroPython, Tema 16.
import statistics

humedades = [d["humedad_pct"] for d in datos]
print(f"Media:    {statistics.mean(humedades):.1f} %")
print(f"Mediana:  {statistics.median(humedades):.1f} %")
print(f"Desv. típica: {statistics.stdev(humedades):.1f} %")
Tu propio módulo. Si guardas tus funciones de conversión y de registro en un archivo kr1.py, cualquier programa puede usarlas con import kr1. Eso es la modularización que pide el currículo, y es lo que permite que el programa de la placa y el análisis de datos del ordenador compartan exactamente la misma función de calibración, sin copiarla dos veces. Y cuando se recalibre el sensor, se toca un archivo.

10. Errores y depuración

Los tres tipos de error, y cómo se atacan
TipoCuándo apareceCómo se localiza
De sintaxisAntes de ejecutar nada: el intérprete no entiende la escritura.El mensaje señala la línea. Mirar también la anterior.
De ejecución (excepción)Durante la ejecución: IndexError, ZeroDivisionError, ValueError, KeyErrorLa traza dice el tipo, la línea y el camino recorrido.
LógicoNunca avisa: el programa termina y el resultado está mal.Casos de prueba, traza y depurador. Es el 90 % del tiempo de depuración.
Cómo se lee una traza de excepciónSe lee de abajo arriba. La última línea da el tipo y la descripción. La penúltima, el archivo y el número de línea donde ocurrió. Encima está la cadena de llamadas: qué función llamó a qué. Y hay un detalle valioso: la línea que falla no siempre es la línea culpable. Un ZeroDivisionError en la línea 40 suele tener su origen en la línea 12, donde una lista se quedó vacía. La traza dice dónde se rompió; encontrar por qué es el trabajo.

Las tres herramientas de depuración, de peor a mejor

1. print()

Imprimir el valor de las variables en puntos clave. Es tosco, funciona siempre y es lo único disponible dentro de la placa. Regla: imprime el nombre junto al valor.

2. assert

Comprobar que una condición se cumple justo donde debe. Detiene el programa en el punto exacto en que el estado deja de ser correcto, en lugar de quinientas líneas después.

3. El depurador

Ejecutar paso a paso viendo el valor de todas las variables. Es la traza del Tema 14, generada automáticamente. En Thonny está a un clic.

Depurar paso a paso con Thonny

1 · Punto de interrupción

Pulsar sobre el número de línea donde quieres que el programa se detenga. Se elige la primera línea donde sospechas que algo va mal.

2 · Ejecutar en modo depuración

El programa arranca y se detiene en ese punto, con el estado completo a la vista.

3 · Inspeccionar variables

Thonny muestra todas las variables y su valor. Aquí se responde a «¿en qué paso deja de ser lo que esperaba?».

4 · Avanzar

Paso a paso: ejecutar la línea siguiente, o entrar dentro de la función que se llama para ver qué hace por dentro.

5 · Corregir y volver a probar

Y añadir un caso de prueba que reproduzca el fallo, para que si vuelve, avise.

El método de depuración, en cuatro pasos1. Reproducir el fallo de forma fiable: un error que aparece «a veces» no se puede corregir, solo tapar. 2. Acotar: partir el programa por la mitad y comprobar en qué mitad está el problema. 3. Formular una hipótesis concreta y comprobarla con una sola medida, como en el Tema 9. 4. Corregir y añadir la prueba que impida que vuelva. Cambiar cosas al azar hasta que funcione no es depurar: es dejar el error donde estaba, esperando.
Batería de casos de prueba: lo que hay que probar siempreEl caso normal, que suele funcionar. El caso vacío: lista sin elementos, archivo sin líneas. Un solo elemento, donde fallan muchos bucles. Los límites: exactamente el umbral, el primer y el último índice. Valores imposibles: negativos, 4095, texto donde iba un número. Y el caso que ya falló una vez, que es el más valioso de todos y el que más se olvida añadir.
# La batería de pruebas de la función del Tema 14, completa
assert media_valida([420, 515]) == 467.5             # normal
assert media_valida([]) is None                      # lista vacía
assert media_valida([420]) == 420                    # un solo elemento
assert media_valida([4095, 4095]) is None            # todas no válidas
assert media_valida([0, 4090]) == 2045               # los límites, incluidos
print("Las cinco pruebas pasan")

Comprueba lo que has aprendido

Este tema se demuestra con un registro real, una gráfica con conclusión y una sesión de depuración documentada.

Qué debería mostrar tu trabajo
AspectoQué debes demostrarEvidencias posibles
Estructuras de datosQue eliges lista, tupla o diccionario con criterio y lo justificas.Histórico como lista de diccionarios, calibración como tupla y una frase que explique cada elección.
RegistroQue las medidas sobreviven al apagado y se pueden volver a leer.Archivo CSV real con cientos de líneas y la función de carga que descarta líneas corruptas.
Análisis y gráficaQue conviertes la serie en una conclusión.Gráfica con título, ejes rotulados con unidad y línea de umbral; cálculo del agua consumida.
ModularizaciónQue tus funciones están en un módulo propio reutilizado por dos programas.Archivo kr1.py importado tanto por el programa de la placa como por el análisis.
DepuraciónQue aplicas el método y no cambias cosas al azar.Un fallo documentado con sus cuatro pasos, captura del depurador con el punto de interrupción y la prueba añadida.
PruebasQue tu batería cubre los casos límite.Cinco assert con caso normal, vacío, único, límites y valores imposibles.

Cierre del aprendizaje del lenguaje: con el Tema 16 el KR-1 saldrá a la red, y a partir del Bloque F Python ya no se explica, se usa.

Glosario del tema

Biblioteca
Conjunto de módulos con funciones reutilizables.
Clave
Nombre con el que se accede a un valor dentro de un diccionario.
Comprensión de lista
Expresión que construye una lista nueva recorriendo otra en una sola línea.
CSV
Formato de archivo de texto con una fila por línea y campos separados por un carácter.
Depuración
Proceso de localizar y corregir la causa de un comportamiento incorrecto.
Depurador
Herramienta que ejecuta un programa paso a paso mostrando el valor de las variables.
Diccionario
Estructura que guarda pares de clave y valor, con acceso por nombre.
Excepción
Error que se produce durante la ejecución e interrumpe el programa.
Índice
Posición de un elemento en una secuencia; el primero es el cero.
Inmutable
Que no se puede modificar después de creado, como una tupla o una cadena.
JSON
Formato de intercambio de datos en texto, equivalente a un diccionario; se usa en el Tema 16.
Lista
Colección ordenada y modificable de elementos.
Mediana
Valor central de una serie ordenada; más robusta que la media frente a valores disparatados.
Modularización
Organización del código en módulos reutilizables e independientes.
Módulo
Archivo con funciones que puede importarse desde otro programa.
Punto de interrupción
Línea en la que se pide al depurador que detenga la ejecución.
Traza de excepción
Informe que indica el tipo de error, la línea y la cadena de llamadas que llevó hasta él.
Troceado
Extracción de una parte de una secuencia indicando el índice inicial y el final.
Tupla
Colección ordenada e inmutable de elementos.

Resumen esencial

  1. Una lista guarda muchos valores en orden; el primer índice es el 0 y el último, len − 1.
  2. El índice negativo -1 es el último elemento y evita la mitad de los errores de índice.
  3. En series con ruido o fallos, la mediana es más robusta que la media: elegir una u otra es decidir cómo se comporta el sistema cuando un sensor falla.
  4. Una tupla es inmutable: sirve para datos que no deben cambiar y para devolver varios valores de una función.
  5. Un diccionario guarda cada dato con su nombre, y eso es lo que hace legible el histórico de un proyecto seis meses después.
  6. El formato JSON del Tema 16 es, para lo que nos interesa, un diccionario escrito como texto.
  7. Una cadena es una secuencia: split, strip y replace son la limpieza previa a toda conversión de un dato externo.
  8. Muchos datos iguales, lista; datos distintos con nombre, diccionario; datos que no cambian, tupla; un histórico, lista de diccionarios.
  9. with open(...) cierra el archivo aunque el programa falle; y confundir el modo "a" con "w" borra el registro de todo el verano.
  10. Un archivo real siempre tiene líneas malas: un lector robusto descarta las vacías y las que no tienen los campos esperados.
  11. Una gráfica técnica lleva título, ejes rotulados con unidad, escala razonable y las referencias que permiten interpretarla.
  12. El proceso de desarrollo es edición, interpretación o compilación, ejecución, pruebas y depuración, y siempre otra vuelta.
  13. En un lenguaje interpretado, lo que no se ejecuta no se comprueba: una errata en una rama que nunca se cumple espera hasta agosto.
  14. Guardar tus funciones en un módulo propio permite que la placa y el análisis compartan la misma calibración.
  15. Hay tres tipos de error: sintaxis, ejecución y lógico; el lógico no avisa y consume la mayor parte del tiempo de depuración.
  16. La traza se lee de abajo arriba, y la línea que falla no siempre es la línea culpable.
  17. Depurar es reproducir, acotar, formular una hipótesis y corregir añadiendo la prueba que impida que vuelva.
  18. La batería de pruebas cubre siempre el caso normal, el vacío, el de un elemento, los límites, los valores imposibles y el que ya falló una vez.

Fuentes y recursos fiables