Evolución Arquitectónica del Sistema
El desarrollo de un sistema de evaluación automática requiere un enfoque iterativo para manejar la complejidad creciente. Inicialmente, el sistema se limitaba a procesar preguntas básicas y respuestas de usuario. En iteraciones posteriores, se incorporó la gestión de exámenes completos, validación de integridad de respuestas, procesamiento de datos de estudiantes y manejo de operaciones de eliminación de preguntas.
Diseño de Clases y Estructura de Datos
Para soportar estas funcionalidades, la arquitectura se divide en varios componentes clave:
- ExamQuestion: Encapsula los datos de una pregunta individual, incluyendo su identificador único, el enunciado y la respuesta esperada.
- TestPaper: Gestiona la composición de un examen, mapeando identificadores de preguntas a sus respectivos pesos o puntuaciones.
- StudentResponse: Representa las respuestas enviadas por un estudiante para un examen específico.
- StudentProfile: Almacena la información demográfica y académica del estudiante, como su ID y nombre completo.
Procesamiento y Validación de Entradas
Un desafío crítico en este tipo de sistemas es el análisis sintáctico (parsing) de las entradas de texto. En lugar de depender de divisiones de cadenas simples que pueden fallar con formatos inesperados, es recomendalbe implementar validaciones estrictas.
Validación de Formato de Preguntas
Para evitar excepciones de índice al procesar entradas malformadas, se debe verificar la presencia de todos los delimitadores requeridos antes de extraer los datos.
// Procesamiento robusto de preguntas utilizando expresiones regulares
Pattern questionPattern = Pattern.compile("#N:(\\d+)\\s+#Q:(.+?)\\s+#A:(.+)");
for (int i = 0; i < totalQuestions; i++) {
String rawInput = scanner.nextLine();
Matcher matcher = questionPattern.matcher(rawInput);
if (!matcher.matches()) {
System.err.println("Error de formato en la línea: " + rawInput);
continue;
}
int qId = Integer.parseInt(matcher.group(1));
String qText = matcher.group(2).trim();
String qAnswer = matcher.group(3).trim();
questionBank.add(new ExamQuestion(qId, qText, qAnswer));
}
Gestión de Respuestas Incompletas
Durante la evaluación, los estudiantes pueden omitir ciertas preguntas. El sistema debe detectar estas omisiones, registrar una advertencia y asignar un valor nulo para mantener la alineación con el examen original.
// Verificación y relleno de respuestas faltantes
int expectedSize = currentPaper.getQuestionCount();
int actualSize = response.getAnswers().size();
if (actualSize < expectedSize) {
int missingCount = expectedSize - actualSize;
System.out.printf("Advertencia: Faltan %d respuestas en el examen %d.%n", missingCount, response.getPaperId());
// Rellenar con valores nulos para mantener la consistencia de los índices
for (int i = 0; i < missingCount; i++) {
response.appendAnswer(null);
}
}
Optimización de Estructuras de Datos
El uso de HashMap estándar para almacenar preguntas y exámenes puede resultar en un orden de iteración impredecible. Dado que el orden de las preguntas es crucial para la presentación del examen y la calificación, se debe utilizar LinkedHashMap.
// Uso de LinkedHashMap para preservar el orden de inserción
Map<Integer, ExamQuestion> questionRegistry = new LinkedHashMap<>();
Map<Integer, TestPaper> paperRegistry = new LinkedHashMap<>();
Control de Duplicidad de Identificadores
Al cargar preguntas desde un archivo o consola, es posible encontrar identificadores duplicados. Sobrescribir silenciosamente los datos existentes puede llevar a errores de calificación. Es fundamental implementar una lógica de detección de colisiones.
// Manejo de IDs duplicados durante el registro de preguntas
if (line.startsWith("#N:")) {
try {
String[] tokens = line.split("\\s+");
int id = Integer.parseInt(tokens[0].substring(3));
String text = tokens[1].substring(3);
String answer = tokens[2].substring(3);
// putIfAbsent devuelve el valor existente si la clave ya está presente
ExamQuestion existing = questionRegistry.putIfAbsent(id, new ExamQuestion(id, text, answer));
if (existing != null) {
System.out.println("Alerta: ID de pregunta duplicado detectado: " + id);
}
} catch (Exception ex) {
System.err.println("Formato inválido al procesar la pregunta: " + line);
}
}
Reflexiones Técnicas y Áreas de Mejora
A lo largo de las iteraciones, se identificaron varias áreas donde el diseño puede optimizarse:
- Manejo de Excepciones: Reemplazar las salidas de error estándar por un sistema de logging estructurado y lanzar excepciones personalizadas para errores de formato.
- Flexibilidad en la Evaluación: Implementar algoritmos de coincidencia difusa (fuzzy matching) o normalización de cadenas (como ignorar mayúsculas/minúsculas y espacios en blanco) para evaluar respuestas de texto libre.
- Desacoplamiento del Parsing: Extraer la lógica de análisis sintáctico del método principal hacia clases dedicadas (por ejemplo,
QuestionParser,PaperParser), aplicando el principio de responsabilidad única.