Última parte.
Read this chapter in English: EN
Aquí cerramos con dos cosas que determinan si un proyecto aguanta iteraciones reales: persistencia y tests.
Código de referencia:
- src/tasks/ports/outputs/task_repository.rs
- src/tasks/adapters/persistence/in_memory_task_repository.rs
- src/tasks/adapters/persistence/json_file_task_repository.rs
Puerto primero, implementación después #
Antes de tocar disco, definimos el contrato TaskRepository.
Por qué esto en vez de llamar JSON desde casos de uso #
Si el caso de uso conoce JSON:
- depende de
serde, - depende de rutas,
- depende de errores de I/O,
- y deja de ser caso de uso para convertirse en script de infraestructura.
Con puerto, aplicación solo conoce operaciones de negocio (save, find, list, delete).
Dos adapters, dos responsabilidades #
InMemoryTaskRepository:
- rápido,
- ideal para tests de comportamiento,
- sin latencia de filesystem.
JsonFileTaskRepository:
- persistencia real,
- serialización,
- errores de lectura/escritura/parsing.
Esto permite testear cada cosa donde corresponde.
Decisiones técnicas de persistencia JSON #
- Ruta de datos en directorio de configuración de plataforma (con
directories). - Creación de directorios si faltan (
create_dir_all). - Archivo ausente = estado vacío (caso normal de primera ejecución).
- JSON inválido = error explícito, no autocorrección silenciosa.
Por qué no autocorregir JSON corrupto #
Porque “arreglar” de forma automática suele equivaler a perder datos sin aviso.
Preferimos fallar con contexto y dejar al usuario decidir recuperación.
Semántica que quedó estabilizada #
save: upsert porid.list:AlloByStatus.find_by_id:Option<Task>.delete:bool(si borró o no).
Este diseño simplifica la CLI porque evita mezclar errores reales con resultados esperables (not found en delete).
Estrategia de pruebas #
Se testea en ambos adapters:
- guardar y recuperar,
- listar y filtrar,
- delete existente/no existente,
- persistencia entre instancias (JSON),
- JSON inválido retorna error.
Con tempdir en JSON tests, no se toca filesystem real del usuario.
Commits que complementan esta parte #
Si quieres ver el orden evolutivo:
Se ve bien cómo primero se implementa comportamiento y luego se endurece con pruebas.
Deuda técnica explícita (que no escondimos) #
Hay cosas intencionalmente pendientes:
RepoErrortodavía es bastante genérico.- no hay locking de archivo para concurrencia.
- no hay migración/versionado del JSON.
Para el alcance del reto está bien. Para escalar a multi-proceso o uso intensivo, serían los siguientes pasos.
Cierre de la serie #
El proyecto empezó como “To-Do de consola” y terminó siendo un ejercicio completo de diseño en Rust:
- dominio con invariantes,
- casos de uso acotados,
- adapters intercambiables,
- contrato CLI usable,
- y pruebas orientadas a comportamiento.
Ese es el verdadero valor del proyecto: usar algo pequeño para practicar decisiones grandes.