Ir al contenido

IDEAS PRÁCTICAS · ASIMOV INGENIERÍA

Metodología de la programación estructurada

Metodología de la programación estructurada

Imagen ilustrativa · Christopher Gower / Unsplash.

Table of contents

No titles in the blog post

Metodología de la programación estructurada: del análisis al código en Python

Objetivo: El alumno identificará los elementos del análisis, diseño y programación estructurados, y apreciará su importancia en el desarrollo de programas.

Pantalla de computadora con código resaltado
Imagen ilustrativa · Mohammad Rahmani / Unsplash.
Tiempo de lectura: 8–10 minutos
En este artículo recorrerás la metodología de la programación estructurada a través de un ejemplo guía (un mini sistema de gestión de alumnos), empleando análisis, diseño modular, seudocódigo, diagramas, procedimientos recurrentes, referencias (apuntadores en sentido lógico) y operaciones CRUD con estructuras de datos en Python.
3.1 La programación estructurada

La programación estructurada es un paradigma que promueve escribir software claro, correcto y mantenible mediante:

  • Control de flujo con tres estructuras básicas: secuencia, selección (if/elif/else) e iteración (while/for).
  • Descomposición modular: dividir el problema en subproblemas (módulos) independientes y cohesionados.
  • Refinamiento sucesivo: del panorama general al detalle, paso a paso.
  • Diseño previo al código: seudocódigo, diagramas y tablas de decisión.
Ejemplo guía que usaremos

“Sistema de Gestión de Alumnos” (SGA) con operaciones para: alta, consulta, actualización, baja, cálculo de promedios y reporte de aprobación.

3.1.1 Definición del problema

Plantea el objetivo, las entradas, salidas, restricciones y casos de prueba. Una buena definición reduce riesgos de re-trabajo.

Objetivo: Administrar alumnos con sus calificaciones y asistencia para determinar si aprueban.

  • Entradas: matrícula, nombre, lista de calificaciones, porcentaje de asistencia.
  • Salidas: reportes, promedio por alumno, estado Aprobado/Reprobado.
  • Restricciones: matrícula única; calificaciones 0–100; asistencia 0–100.

Datos de prueba iniciales:

  • A001, “Ana”, [80, 90, 75], asistencia 92
  • A002, “Luis”, [60, 70, 65], asistencia 78
3.1.2 Identificación de los módulos (subproblemas)
  • Entrada y validación de datos
  • Almacenamiento y búsqueda
  • Cálculo de promedio
  • Determinación de aprobación
  • Actualización y eliminación
  • Reporte

Nota de diseño: cada módulo será una función en Python. Evita efectos laterales innecesarios, y haz que cada función haga “una sola cosa bien”.

# Esqueleto de funciones (stubs)
def crear_alumno(db, matricula, nombre, calificaciones, asistencia): ...
def listar_alumnos(db): ...
def buscar_alumno(db, matricula): ...
def actualizar_alumno(db, matricula, **cambios): ...
def eliminar_alumno(db, matricula): ...
def calcular_promedio(calificaciones): ...
def esta_aprobado(promedio, asistencia): ...
3.1.3 Refinamiento sucesivo de los módulos

Refina cada módulo en pasos más simples hasta que el paso pueda traducirse directamente a código.

3.1.3.1 Seudocódigo y diagramas estructurados
INICIO SGA
  MIENTRAS usuario no elija SALIR
    mostrar_menu()
    opcion ← leer_opcion()
    SI opcion = ALTA ENTONCES
       datos ← capturar_datos_alumno()
       crear_alumno(db, datos)
    SINO SI opcion = CONSULTA ENTONCES
       listar_alumnos(db)
    SINO SI opcion = ACTUALIZAR ENTONCES
       matricula ← leer_matricula()
       cambios ← capturar_cambios()
       actualizar_alumno(db, matricula, cambios)
    SINO SI opcion = BAJA ENTONCES
       matricula ← leer_matricula()
       eliminar_alumno(db, matricula)
    SINO SI opcion = REPORTE ENTONCES
       generar_reporte(db)
    FIN SI
  FIN MIENTRAS
FIN
3.1.3.2 El árbol y la tabla de decisiones

Árbol de módulos (resumen)

  • Sistema de Gestión de Alumnos
    • Entrada y validación
    • Gestión de alumnos
      • Alta
      • Consulta
      • Actualización
      • Baja
    • Cálculo de promedio
    • Determinación de aprobación
    • Reporte
Tabla de decisiones para estado “Aprobado”
Condición Regla 1 Regla 2 Regla 3 Regla 4
Promedio ≥ 70SíNoNoSí
Asistencia ≥ 80SíSíNoNo
Acción: EstadoAprobadoReprobadoReprobadoReprobado
Se puede extender con más reglas (extraordinario, recuperación, etc.).
3.2 Procedimientos recurrentes

Un procedimiento recurrente (recursivo) se define en términos de sí mismo. Útil para estructuras jerárquicas (árboles) o descomposición natural del problema.

Ejemplo 1: suma recursiva
def suma(lista):
    # Caso base
    if not lista:
        return 0
    # Caso recursivo
    return lista[0] + suma(lista[1:])

print(suma([1, 2, 3, 4]))  # 10
Ejemplo 2: imprimir árbol de módulos
arbol = {
    "SGA": ["Entrada", {"Gestión": ["Alta", "Consulta", "Actualización", "Baja"]},
            "Promedio", "Aprobación", "Reporte"]
}

def imprimir_arbol(nodo, nivel=0):
    for k, hijos in nodo.items():
        print("  " * nivel + "- " + k)
        for h in hijos:
            if isinstance(h, dict):
                imprimir_arbol(h, nivel + 1)
            else:
                print("  " * (nivel + 1) + f"- {h}")

imprimir_arbol(arbol)
Ejercicio: implementa una función recursiva que calcule el promedio de una lista de calificaciones sin usar sum() ni len(). Pista: devuelve (suma, cuenta) en cada llamada.
3.3 Uso de apuntadores

En Python no existen “apuntadores” como en C, pero las variables hacen referencia a objetos en memoria. Comprender referencias y mutabilidad evita errores sutiles.

Alias y mutabilidad
alfa = [1, 2, 3]
beta = alfa         # beta referencia el mismo objeto
beta.append(4)
print(alfa)  # [1, 2, 3, 4]  ¡ambas referencias apuntan al mismo objeto!
Copias seguras
import copy
gamma = [1, [2, 3]]
shallow = gamma.copy()      # copia superficial
deep = copy.deepcopy(gamma) # copia profunda
gamma[1].append(4)
print(shallow)  # [1, [2, 3, 4]]
print(deep)     # [1, [2, 3]]
Buenas prácticas: documenta si tus funciones modifican sus argumentos; evita mutar estructuras recibidas salvo que sea el comportamiento esperado; usa copias cuando corresponda.
3.4 Almacenamiento, actualización y eliminación de información en base a estructuras

Implementemos operaciones CRUD sobre una estructura en memoria. Usaremos un diccionario indexado por matrícula que almacena diccionarios por alumno.

Práctica guiada: mini-CRUD estructurado en Python
# Base de datos en memoria
alumnos = {}  # {"A001": {"nombre": "...","calificaciones":[...], "asistencia": 0-100}}

def crear_alumno(db, matricula, nombre, calificaciones, asistencia):
    if matricula in db:
        raise ValueError("La matrícula ya existe.")
    if not (0 <= asistencia <= 100):
        raise ValueError("Asistencia fuera de rango.")
    if not all(0 <= c <= 100 for c in calificaciones):
        raise ValueError("Calificación fuera de rango.")
    db[matricula] = {
        "nombre": nombre.strip(),
        "calificaciones": list(calificaciones),
        "asistencia": float(asistencia)
    }

def listar_alumnos(db):
    for mat, datos in db.items():
        prom = calcular_promedio(datos["calificaciones"])
        estado = "Aprobado" if esta_aprobado(prom, datos["asistencia"]) else "Reprobado"
        print(f"{mat} | {datos['nombre']:10s} | Prom: {prom:5.1f} | Asist: {datos['asistencia']:5.1f}% | {estado}")

def buscar_alumno(db, matricula):
    return db.get(matricula)

def actualizar_alumno(db, matricula, **cambios):
    if matricula not in db:
        raise KeyError("No existe la matrícula.")
    registro = db[matricula]
    if "nombre" in cambios:
        registro["nombre"] = cambios["nombre"].strip()
    if "calificaciones" in cambios:
        cal = cambios["calificaciones"]
        if not all(0 <= c <= 100 for c in cal):
            raise ValueError("Calificación fuera de rango.")
        registro["calificaciones"] = list(cal)
    if "asistencia" in cambios:
        asist = float(cambios["asistencia"])
        if not (0 <= asist <= 100):
            raise ValueError("Asistencia fuera de rango.")
        registro["asistencia"] = asist

def eliminar_alumno(db, matricula):
    if matricula in db:
        del db[matricula]

def calcular_promedio(calificaciones):
    return sum(calificaciones)/len(calificaciones) if calificaciones else 0.0

def esta_aprobado(promedio, asistencia):
    return promedio >= 70 and asistencia >= 80

# Demostración
if __name__ == "__main__":
    crear_alumno(alumnos, "A001", "Ana", [80, 90, 75], 92)
    crear_alumno(alumnos, "A002", "Luis", [60, 70, 65], 78)
    actualizar_alumno(alumnos, "A002", calificaciones=[70, 80, 85], asistencia=82)
    listar_alumnos(alumnos)
    print("— Eliminando A001 —")
    eliminar_alumno(alumnos, "A001")
    listar_alumnos(alumnos)
Ejercicios propuestos
  • Agrega validación para evitar listas vacías de calificaciones.
  • Implementa función reporte_csv(db, ruta) que exporte los datos.
  • Agrega un campo “grupo” y crea un reporte por grupo.
  • Implementa confirmación de borrado (sí/no) antes de eliminar.
Buenas prácticas estructuradas
  • Una función, una responsabilidad.
  • Validación de entradas en los límites del módulo.
  • Evita estados globales; pasa estructuras como parámetros.
  • Pruebas con datos de borde (0, 100, listas vacías, duplicados).
Resumen

La programación estructurada proporciona un marco claro para pasar del análisis al diseño y de ahí al código. El uso de módulos, refinamiento sucesivo, seudocódigo, diagramas y tablas de decisión reduce la complejidad y mejora la mantenibilidad. En Python, comprender las referencias y las estructuras de datos te permitirá implementar CRUDs limpios y seguros.

¿Qué sigue?

Convierte el mini-CRUD en una aplicación de línea de comandos completa con menú, manejo de errores y persistencia en archivo JSON.

¿Dudas o mejoras? Comparte tus preguntas y propuestas para ampliar este ejemplo a una API o a una interfaz web.