Sesión 11

Colecciones dinámicas, depuración y sistemas interactivos

Unidad 2 · Preparación arquitectónica para el Proyecto Integrador (Entrega 2)

Navegación: ← → · Home / End · F pantalla completa · Táctil: desliza

Propósito de la sesión

Fundamentos de escalabilidad iterativa

  • Comprender la diferencia de asignación de memoria y complejidad operativa entre un arreglo estático y una lista genérica (List<T>).
  • Diseñar patrones de menús continuos utilizando ciclos do-while acoplados a bloques de decisión switch.
  • Trazar el estado de la memoria a través de pruebas de escritorio rigurosas sobre estructuras de datos.
  • Definir la arquitectura de software esperada para la Entrega 2 del Proyecto Integrador.
Almacenamiento: Estático vs Dinámico

Arreglos (T[])

  • Tamaño inmutable: Se define en tiempo de instanciación. La reasignación implica crear un arreglo nuevo y copiar los datos, lo cual tiene un costo computacional O(N).
  • Gestión de memoria: Asignación contigua en el Heap. Alta eficiencia de acceso por índice (O(1)) y baja sobrecarga.
  • Ideal cuando el volumen del conjunto de datos es una variable conocida a priori.

Listas (List<T>)

  • Tamaño dinámico: Capacidad auto-redimensionable. Internamente, utiliza un arreglo que duplica su capacidad (algoritmo de crecimiento) cuando se agota el espacio.
  • Flexibilidad operativa: Permite agregar, remover o insertar elementos sin gestionar índices manuales.
  • Ideal para datos cuyo volumen de captura en tiempo de ejecución es incierto.
Implementación de List<T> en C#

Sintaxis y métodos fundamentales

// Inclusión obligatoria del espacio de nombres using System.Collections.Generic; // Instanciación List<double> mediciones = new List<double>(); // Mutación de estado mediciones.Add(24.5); // Añade al final de la colección mediciones.Add(26.1); // Consulta de estado int elementosActuales = mediciones.Count; // Ojo: Count, no Length // Acceso O(1) por indexador double primeraMedicion = mediciones[0];

Nota técnica: La propiedad Capacity (memoria reservada) es distinta a Count (elementos lógicos reales). El motor de .NET gestiona el crecimiento de Capacity automáticamente para mantener el costo amortizado de Add en O(1).

Arquitectura de un Sistema Continuo

El paradigma REPL

Los sistemas no modulares interactivos operan bajo un ciclo de vida REPL extendido (Read-Eval-Print Loop):

  • Read: Captura la intención del usuario.
  • Eval: Ejecuta la regla de negocio.
  • Print: Emite retroalimentación.
  • Loop: Repite hasta una condición de salida explícita.

Herramienta idónea: do-while

Al requerir presentar la interfaz (menú) antes de evaluar cualquier decisión, la estructura do-while garantiza al menos un flujo de ejecución, eliminando redundancias en la invocación de funciones de entrada.

Implementación del Menú Base (do-while)
bool sistemaActivo = true; do { Console.Clear(); Console.WriteLine("=== SISTEMA DE MONITOREO ==="); Console.WriteLine("1. Registrar nueva medición"); Console.WriteLine("2. Ver estadísticas globales"); Console.WriteLine("0. Finalizar sistema"); Console.Write("Seleccione una opción: "); string entrada = Console.ReadLine(); switch (entrada) { case "1": // Bloque lógico de captura break; case "2": // Bloque lógico de procesamiento break; case "0": sistemaActivo = false; Console.WriteLine("Cerrando sesión de trabajo..."); break; default: Console.WriteLine("Comando no reconocido. Presione Enter para continuar."); Console.ReadLine(); break; } } while (sistemaActivo);
Conexión: Colecciones + Menú Persistente

El alcance de la colección

Para que la colección persista entre múltiples selecciones del usuario, su declaración e instanciación debe realizarse antes y fuera del ciclo do-while.

List<double> datos = new List<double>(); do { // El ciclo utiliza y muta "datos" } while (...);

Riesgos comunes

  • Declarar la lista dentro del ciclo reiniciará el conjunto de datos a vacío en cada iteración (pérdida catastrófica de memoria).
  • Intentar realizar estadísticas sobre una colección vacía arrojará excepciones (ej. división por cero al calcular un promedio). La validación defensiva es estricta.
Procesamiento Estadístico Iterativo

Generación de reportes recorriendo la colección

if (datos.Count == 0) { Console.WriteLine("No hay registros para procesar."); } else { double suma = 0.0; double maximo = double.MinValue; int umbralSuperado = 0; // Recorrido O(N) lineal estricto for (int i = 0; i < datos.Count; i++) { double valorActual = datos[i]; suma += valorActual; if (valorActual > maximo) maximo = valorActual; if (valorActual > 50.0) umbralSuperado++; } double media = suma / datos.Count; // La impresión de las métricas ocurre aquí }
Robustez: Programación Defensiva

El problema de Parse

int.Parse o double.Parse confía incondicionalmente en que el usuario ingresará datos numéricos válidos. Si ingresa texto, se dispara una FormatException y el sistema colapsa.

La solución: TryParse

Utilizar métodos de tipo Try permite evaluar y capturar en un solo paso, devolviendo una bandera booleana.

Console.Write("Ingrese valor: "); string input = Console.ReadLine(); double valor; if (double.TryParse(input, out valor)) { datos.Add(valor); } else { Console.WriteLine("Error de tipado."); }
Pruebas de Escritorio con Colecciones

Rastreo del estado de memoria en tiempo de iteración

Paso / Iteración Acción / Entrada datos.Count Estado Lógico de datos suma (Temp)
Inicialización N/A 0 [ ] 0.0
Ejecuta Opción 1 Ingresa 12.5 1 [ 12.5 ] 0.0
Ejecuta Opción 1 Ingresa 8.0 2 [ 12.5, 8.0 ] 0.0
Ejecuta Opción 2 Recorrido i = 0 2 [ 12.5, 8.0 ] 12.5
Ejecuta Opción 2 Recorrido i = 1 2 [ 12.5, 8.0 ] 20.5

La prueba de escritorio revela que las métricas (como la suma) deben aislarse en variables temporales que se reinicien al invocar el reporte, protegiendo el dato crudo.

Depuración Analítica en Entorno Local

Inspección de estado con VS Code

  • Breakpoints (F9): Detienen la ejecución en una línea específica sin matar el proceso.
  • Step Over (F10): Ejecuta la instrucción actual y avanza secuencialmente.
  • Panel "Variables": Expande objetos complejos como List<T> para inspeccionar sus índices internos en tiempo real.

Localización de cuellos de botella

La depuración permite identificar si un ciclo infinito fue provocado por una actualización faltante del contador (ej. omitir i++) o si una condición de escape (break) jamás se evalúa a verdadero debido a discrepancias en el tipo de dato.

Arquitectura Esperada: Proyecto Entrega 2

Especificación Técnica

Evolución del sistema: El código monolítico y secuencial de la Unidad 1 debe ser reescrito bajo un paradigma iterativo.

  • Debe implementar un menú de control principal (do-while + switch o if/else lógicos).
  • Debe ser capaz de procesar múltiples entidades en una sola sesión (uso de List<T> o arreglos bien controlados).
  • Debe integrar un submódulo de generación de reportes apoyado en ciclos (for o foreach) para procesar métricas sobre la colección ingresada.
  • Cero colapsos por excepciones de formato (uso obligatorio de validaciones).
Estándares de Calidad a Nivel Ingeniería

Código Limpio (Clean Code)

  • Sin "Números Mágicos": Las constantes límite (ej. límite de calificación = 5.0) deben estar declaradas en variables documentadas.
  • Nombres semánticos: Una variable se llama listaPresiones, no lista1 ni x.
  • Comentarios de justificación: Comenta el por qué se toma una decisión algorítmica, no el qué hace una instrucción obvia de sintaxis.

Deuda Técnica Cero

El código generado en esta entrega deberá ser modularizado (dividido en funciones) en la Unidad 3. Si el bloque de casos del menú crece más allá de 30-40 líneas, se está inyectando deuda técnica. Mantener las lógicas enfocadas preparará el terreno para las firmas de métodos.

Fase de Trabajo y Modelado Arquitectónico

Preparación del Taller (Resto de la sesión)

  • Construir en diagrama (Draw.io/Lucidchart) o pseudocódigo la estructura de navegación del proyecto propio.
  • Identificar la estructura de almacenamiento primaria: ¿Qué entidad modela el List (precios, edades, niveles de tanque, velocidades)?
  • Redactar el archivo README del repositorio indicando cómo ejecutar el programa iterativo y qué validar en las entradas.
  • Realizar un commit de base en GitHub con la estructura do-while en limpio, antes de integrar lógica condicional profunda.
Cierre Estructural

Resumen de Competencias Consolidadas

  • La transición de variables atómicas a colecciones dinámicas representa un salto cuántico en la utilidad del software.
  • El uso riguroso de iteradores requiere control preciso de fronteras de memoria (índices, capacidades, acumuladores temporales).
  • Los sistemas iterativos que capturan, procesan y retienen estado forman la base conceptual de todos los sistemas de información transaccionales en la industria.
  • El proyecto se prepara para ser evaluado no solo por resultados, sino por la defensa de su arquitectura ante desbordamientos y formatos inválidos.