Evaluación 1

Modelado del Dominio POO

Entrega Incremental 1 - Base del Proyecto TaskFlow

15%
Taller Práctico
Fecha límite: 26 de febrero de 2026
¿Qué es el Proyecto Incremental?

TaskFlow es un sistema de gestión de tareas que construirás durante todo el semestre. Esta entrega (E1) es la base. Todo lo que construyas aquí lo usarás en E2, E3, E4, E5 y E6. Es fundamental que quede bien.

Clases Relacionadas

Estas clases preparan los conocimientos necesarios para esta evaluación:

Objetivo de Aprendizaje

Implementar la capa de dominio del sistema TaskFlow utilizando Programación Orientada a Objetos avanzada en Python. Aplicar encapsulamiento, herencia, polimorfismo y clases abstractas.

Modalidad de Trabajo

Individual o en parejas (máximo 2 personas).

Formato de entrega: Repositorio GitHub con código fuente + README.md con instrucciones de ejecución. El repositorio debe ser privado y compartir acceso al docente.

Requisitos Técnicos Detallados

1. Clase Usuario

Descripción: Representa un usuario del sistema TaskFlow que puede crear proyectos y tareas.

Atributos obligatorios:
Métodos obligatorios:
Validaciones requeridas:
  • Username: mínimo 3 caracteres, solo alfanuméricos
  • Email: debe contener @ y punto (validación en setter con @property)
  • Lanzar ValueError con mensaje descriptivo si falla
2. Clase Proyecto

Descripción: Un proyecto agrupa múltiples tareas y tiene un líder (Usuario).

Atributos obligatorios:
Métodos obligatorios:
Relación de composición: El proyecto "posee" las tareas. Si se elimina el proyecto, sus tareas también deberían eliminarse conceptualmente.
3. Clase Tarea

Descripción: Una tarea individual dentro de un proyecto con estado y prioridad.

Atributos obligatorios:
Métodos obligatorios:
4. Enums (enums.py)

Descripción: Definir enumeraciones para tipos seguros usando enum.Enum.

PrioridadTarea:
EstadoTarea:
5. Calidad de Código
Estándares obligatorios:
Ejemplo de docstring formato Google:
def agregar_tarea(self, tarea: Tarea) -> None:
    """Agrega una tarea al proyecto.

    Args:
        tarea: La tarea a agregar. No puede ser None.

    Raises:
        ValueError: Si la tarea es None o ya existe en el proyecto.
    """

Ejemplo de Implementación

src/domain/usuario.py
from datetime import datetime
from typing import Optional


class Usuario:
    """Representa un usuario en el sistema TaskFlow.

    Attributes:
        username: Identificador único del usuario (inmutable).
        email: Correo electrónico validado.
        nombre_completo: Nombre completo del usuario (opcional).
        activo: Estado de la cuenta.
        fecha_registro: Fecha de creación de la cuenta.
    """

    def __init__(
        self,
        username: str,
        email: str,
        nombre_completo: Optional[str] = None
    ) -> None:
        """Inicializa un nuevo usuario.

        Args:
            username: Identificador único (mínimo 3 caracteres, alfanumérico).
            email: Correo electrónico válido.
            nombre_completo: Nombre completo opcional.

        Raises:
            ValueError: Si el username tiene menos de 3 caracteres.
            ValueError: Si el email no tiene formato válido.
        """
        if len(username) < 3:
            raise ValueError("Username debe tener al menos 3 caracteres")
        if not username.isalnum():
            raise ValueError("Username solo puede contener letras y números")

        self._username = username  # Atributo privado (inmutable)
        self._email = None
        self.email = email  # Usa el setter para validar
        self.nombre_completo = nombre_completo
        self.activo = True
        self.fecha_registro = datetime.now()

    @property
    def username(self) -> str:
        """Username inmutable del usuario."""
        return self._username

    @property
    def email(self) -> str:
        """Email del usuario."""
        return self._email

    @email.setter
    def email(self, valor: str) -> None:
        """Valida y asigna el email.

        Args:
            valor: Email a validar.

        Raises:
            ValueError: Si el email no contiene @ o punto.
        """
        if "@" not in valor or "." not in valor:
            raise ValueError(f"Email inválido: {valor}")
        self._email = valor

    def activar(self) -> None:
        """Activa la cuenta del usuario."""
        self.activo = True

    def desactivar(self) -> None:
        """Desactiva la cuenta del usuario."""
        self.activo = False

    def __str__(self) -> str:
        return f"@{self.username}"

    def __repr__(self) -> str:
        return f"Usuario('{self.username}', '{self.email}')"

Estructura de Entrega

Organización de Archivos Obligatoria
src/ ├── __init__.py └── domain/ ├── __init__.py ├── enums.py # PrioridadTarea, EstadoTarea ├── usuario.py # Clase Usuario ├── proyecto.py # Clase Proyecto └── tarea.py # Clase Tarea README.md # Instrucciones para ejecutar el proyecto test_dominio.py # Tests básicos (opcional pero recomendado) requirements.txt # Dependencias (si las hay)

Pasos para Completar la Evaluación

1Crear la estructura de carpetas

Crear src/domain/ con los archivos __init__.py

2Implementar los Enums

Crear PrioridadTarea y EstadoTarea en enums.py

3Implementar la clase Usuario

Con validaciones, properties y type hints

4Implementar la clase Tarea

Usando los enums para prioridad y estado

5Implementar la clase Proyecto

Con la relación de composición con Tarea

6Crear tests básicos

Verificar que todo funcione correctamente

7Documentar en README.md

Cómo ejecutar el código y ejemplos de uso

Rúbrica de Evaluación (100%)

Criterio Excelente (5.0) Aceptable (3.5) Insuficiente Peso
Funcionalidad Todas las clases funcionan correctamente, validaciones robustas, manejo de errores completo Funciona pero validaciones básicas, algunos edge cases sin manejar No funciona o faltan clases principales 30%
Arquitectura POO Excelente encapsulamiento, properties bien usadas, herencia aplicada donde corresponde Uso básico de clases, algunos atributos públicos sin razón No aplica POO, todo procedural o atributos públicos 25%
Type Hints 100% del código tipado correctamente, incluyendo Optional, Union donde corresponde Mayoría tipado, algunos métodos sin tipar Sin type hints o solo algunos 20%
Documentación Docstrings Google style completos en todas las clases y métodos públicos Algunos docstrings presentes, formato inconsistente Sin documentación o solo comentarios 15%
Tests (bonus) Tests exhaustivos con pytest, cubren edge cases y validaciones Tests básicos funcionales, cobertura parcial Sin tests 10%
Penalizaciones
Conexión con E2

El dominio que construyas aquí será la base para E2: Testing y Calidad. Asegúrate de que funcione correctamente porque lo testearás en la siguiente entrega.

← Inicio E2: Testing →