You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Al final de cada capítulo se presenta un reto gamificado, simbolizado por un “Guardián Pokémon”. Estos desafíos buscan reforzar lo aprendido y convertir el recorrido en una experiencia más significativa y memorable.
A continuación se muestra la estructura de retos correspondiente a cada capítulo, diseñada para integrarse de manera natural en la narrativa del curso “El Legado del Desarrollador”.
Nota: Este es un documento vivo. A medida que se complete el código, se agregarán los documentos de referencia con las soluciones correspondientes.
Los retos se presentan en formato narrativo y ofrecen solo los detalles esenciales de implementación siguiendo el modelo MVC tradicional.
No obstante, las soluciones de código se desarrollarán bajo los principios de Screaming Architecture y Arquitectura Hexagonal, que considero una forma más sólida y escalable de estructurar el proyecto.
Para mantener la claridad, los ejemplos se mostrarán utilizando el paquete base com.legacy, con la idea de que posteriormente puedan refactorizarse siguiendo las prácticas arquitectónicas mencionadas.
Capítulo 1: La Aldea Inicial y el Kit del Entrenador
El Reto del Guardián: Derrota a Graveler, el Pokémon Cimiento
Has recibido tu kit de inicio, pero para poder salir de la "Aldea Paleta", debes demostrar que puedes construir una base sólida. Graveler, un Pokémon hecho de roca pura, bloquea el camino. No puedes vencerlo con fuerza, sino con estructura. Debes construir un refugio (tu proyecto) que resista su primer envite.
Caso de Uso (La Misión):
Usa Spring Initializr para generar un nuevo proyecto Spring Boot con las dependencias Spring Web y Kotlin.
Importa el proyecto en tu IntelliJ IDEA.
Crea un paquete com.legacy.controller.
Dentro, crea una clase WelcomeController anotada como @RestController.
Define un endpoint con @GetMapping("/challenge/start") que devuelva un objeto simple (una data class de Kotlin) con un mensaje: {"message": "Mi viaje ha comenzado"}.
Criterios de Victoria (Objetivos de Aprendizaje):
El proyecto se compila y ejecuta sin errores.
Al acceder a http://localhost:8080/challenge/start en tu navegador o Postman, recibes el JSON de bienvenida, si no existe aún tu reto es completar el código.
Recompensa (Conocimiento Adquirido): ¡Has derrotado a Graveler! Has demostrado que dominas la habilidad fundamental de Creación y Estructura de Proyectos. Ahora tienes una base sólida sobre la cual construir el resto de tu aplicación.
Capítulo 2: El Primer Hechizo y el Gremio de Controladores
El Reto del Guardián: Supera a Kadabra, el Pokémon Psíquico
Para ser aceptado en el "Gremio de Controladores", debes demostrar que puedes separar la lógica (el poder psíquico) de la presentación. Kadabra te reta a un duelo mental. Debes crear un sistema donde la lógica de negocio esté separada del controlador que la invoca.
Caso de Uso (La Misión):
Crea un paquete com.legacy.service.
Dentro, crea una clase PokedexService anotada con @Component. Esta clase tendrá una función findPokemonById(id: Int) que devuelve el nombre de un Pokémon usando un when (ej: si id es 1, devuelve "Bulbasaur"; si es 4, "Charmander". Para cualquier otro, "Pokémon no encontrado").
En tu WelcomeController, inyecta el PokedexService usando @Autowired.
Crea un nuevo endpoint @GetMapping("/pokedex/{id}") que llame al método del servicio y devuelva el nombre del Pokémon.
Criterios de Victoria (Objetivos de Aprendizaje):
La inyección de dependencias funciona correctamente.
Al acceder a /pokedex/4, recibes la cadena "Charmander".
Al acceder a /pokedex/99, recibes "Pokémon no encontrado".
Recompensa (Conocimiento Adquirido): ¡Has superado la prueba de Kadabra! Has dominado la Inyección de Dependencias y la Separación de Responsabilidades. Tu código es ahora más organizado, mantenible y poderoso.
Capítulo 3: Las Minas de Datos de Ciudad Plateada
El Reto del Guardián: Captura a Onix, el Pokémon Serpiente Roca
En las profundidades de las minas, te encuentras con Onix, una criatura colosal hecha de datos entrelazados. Para capturarlo, debes crear una estructura capaz de almacenar y gestionar su información.
Caso de Uso (La Misión):
Añade las dependencias Spring Data JPA y H2 Database.
Crea un paquete com.legacy.model y define una @EntityTrainer con un id (Long) y un name (String).
Crea un paquete com.legacy.repository y define una interfaz TrainerRepository que extienda de JpaRepository.
Crea un TrainerController con endpoints para:
POST /trainers: Crear un nuevo entrenador.
GET /trainers: Listar todos los entrenadores.
Criterios de Victoria (Objetivos de Aprendizaje):
La aplicación se conecta a la base de datos H2 en memoria.
Puedes crear un nuevo entrenador enviando un POST con un JSON {"name": "Ash"}.
Puedes ver la lista de entrenadores creados al hacer un GET.
Recompensa (Conocimiento Adquirido): ¡Has capturado a Onix! Ahora posees el poder de la Persistencia de Datos. Puedes modelar, guardar y recuperar información de una base de datos, el pilar de cualquier aplicación real.
Capítulo 4: El Dojo de la Validación y el Manejo de Errores
El Reto del Guardián: Resiste el ataque de Machoke, el Pokémon Superpoder
En el dojo, Machoke te ataca con una ráfaga de "datos inválidos". Tu API debe ser lo suficientemente fuerte y disciplinada para bloquear estos ataques y responder con elegancia, en lugar de romperse.
Caso de Uso (La Misión):
Añade la dependencia Spring Boot Starter Validation.
En tu entidad Trainer, añade la anotación @NotBlank al campo name.
En el método POST /trainers de tu TrainerController, añade la anotación @Valid al cuerpo de la petición.
Crea un @ControllerAdvice global que capture la MethodArgumentNotValidException y devuelva un estado 400 Bad Request con un mensaje de error claro y personalizado en formato JSON.
Criterios de Victoria (Objetivos de Aprendizaje):
Enviar un POST /trainers con {"name": ""} o {"name": null} ya no causa un error 500, sino que devuelve un código 400.
La respuesta del error 400 es el JSON personalizado que definiste.
Recompensa (Conocimiento Adquirido): ¡Has bloqueado el ataque de Machoke! Has dominado el arte de la Validación y el Manejo Profesional de Errores. Tu API es ahora robusta y confiable.
Capítulo 5: La Fortaleza de la Seguridad y el Guardián JWT
El Reto del Guardián: Gánate la lealtad de Arcanine, el Pokémon Legendario
La fortaleza está protegida por el noble Arcanine. No te dejará pasar a menos que le demuestres que eres digno de confianza, presentándole una credencial secreta (un Token JWT).
Caso de Uso (La Misión):
Añade las dependencias de Spring Security y una librería para JWT (ej. jjwt).
Configura Spring Security para que ignore un endpoint público POST /login.
Crea el endpoint POST /login que, para un usuario y contraseña fijos, genere y devuelva un Token JWT.
Asegura el endpoint GET /trainers. Ahora solo debería ser accesible si se proporciona un Token JWT válido en la cabecera Authorization: Bearer <token>.
Criterios de Victoria (Objetivos de Aprendizaje):
Intentar acceder a GET /trainers sin token devuelve un error 401 o 403.
Después de obtener un token de /login, usarlo en la cabecera de GET /trainers permite el acceso.
Recompensa (Conocimiento Adquirido): ¡Arcanine te reconoce como un aliado! Has dominado la Autenticación y Autorización con JWT. Ahora puedes proteger los secretos de tu aplicación.
Capítulo 6: El Oráculo de las Pruebas en la Torre Pokémon
El Reto del Guardián: Engaña a Ditto, el Pokémon Transformación
El Oráculo te presenta a Ditto, un ser que puede transformarse en cualquier parte de tu código para poner a prueba su resistencia. Para vencerlo, debes anticipar sus movimientos y crear pruebas que cubran todas sus formas.
Caso de Uso (La Misión):
Escribe una prueba unitaria para tu PokedexService (del Capítulo 2). Usa Assertions de JUnit para verificar que findPokemonById(1) realmente devuelve "Bulbasaur".
Escribe una prueba de integración para tu TrainerController. Usa @SpringBootTest y MockMvc para simular una llamada POST /trainers y verificar que la respuesta sea un 201 Created.
Criterios de Victoria (Objetivos de Aprendizaje):
Ambas pruebas (unitaria y de integración) se ejecutan y pasan con éxito.
Las pruebas demuestran que el código funciona como se espera sin necesidad de levantar la aplicación completa manualmente.
Recompensa (Conocimiento Adquirido): ¡Has superado el engaño de Ditto! Has adquirido la habilidad de Testing Automatizado. Ahora puedes construir con la confianza de que tu código es correcto y resistente a futuros cambios.
Capítulo 7: El Mapa del Merodeador: Documentando con Swagger
El Reto del Guardián: Interpreta la visión de Xatu, el Pokémon Místico
Xatu puede ver el pasado y el futuro de tu código, pero solo se comunica a través de visiones crípticas. Tu misión es usar el poder de OpenAPI para traducir esas visiones en un mapa claro y comprensible para todos los viajeros (desarrolladores).
Caso de Uso (La Misión):
Añade la dependencia springdoc-openapi-starter-webmvc-ui.
En tu TrainerController, usa la anotación @Operation(summary = "Crea un nuevo Entrenador") en el endpoint POST /trainers.
Añade anotaciones @ApiResponse para documentar la respuesta 201 Created y la 400 Bad Request por validación.
Criterios de Victoria (Objetivos de Aprendizaje):
La interfaz de Swagger UI está disponible en /swagger-ui.html.
El endpoint de creación de entrenadores muestra el resumen y las posibles respuestas que has documentado.
Recompensa (Conocimiento Adquirido): ¡Has traducido la visión de Xatu! Has dominado la Documentación Automática de APIs. Tu trabajo es ahora profesional, claro y fácil de integrar por otros.
Capítulo 8: El Lanzamiento del Poké Ball: Despliegue y Monitoreo
El Reto del Guardián: Atrapa a Gengar, el Pokémon Sombra
Has desplegado tu aplicación, pero un travieso Gengar se esconde en las "sombras" de tu entorno de producción. Puede causar problemas si no lo vigilas. Debes usar herramientas de monitoreo para exponerlo y mantenerlo bajo control.
Caso de Uso (La Misión):
Añade la dependencia Spring Boot Starter Actuator.
Configura en tu application.properties que se expongan los endpoints de health e info (management.endpoints.web.exposure.include=health,info).
Construye tu aplicación como un JAR ejecutable (./gradlew bootJar).
Ejecuta el JAR desde tu terminal (java -jar ...).
Criterios de Victoria (Objetivos de Aprendizaje):
La aplicación se ejecuta correctamente desde el JAR.
Puedes acceder a http://localhost:8080/actuator/health y ver el estado {"status":"UP"}.
Recompensa (Conocimiento Adquirido): ¡Has atrapado a Gengar! Has aprendido los fundamentos del Empaquetado, Despliegue y Monitoreo. Tu aplicación ya no es un juguete, es un servicio listo para el mundo real.
Capítulo 9: La Liga de los Maestros: Temas Avanzados
El Reto del Guardián: Domestica a Jolteon, el Pokémon Relámpago
Para ser un maestro, debes controlar la velocidad del rayo. Jolteon te reta a una carrera. No puedes ganarle en una carrera lineal; debes aprender a hacer varias cosas a la vez, usando el poder de la asincronía.
Caso de Uso (La Misión):
Habilita el soporte asíncrono en tu aplicación con @EnableAsync.
Crea un NotificationService con un método @Async llamado sendWelcomeMessage(trainerName: String). Este método simulará un proceso lento (ej. Thread.sleep(3000)) y luego imprimirá en consola "Mensaje de bienvenida enviado a [trainerName]".
Llama a este método asíncrono desde tu endpoint POST /trainers justo después de guardar al nuevo entrenador.
Criterios de Victoria (Objetivos de Aprendizaje):
Al crear un nuevo entrenador, la respuesta de la API es inmediata.
Aproximadamente 3 segundos después, el mensaje de bienvenida aparece en la consola del servidor.
Recompensa (Conocimiento Adquirido): ¡Has domesticado a Jolteon! Has dominado la Programación Asíncrona. Ahora puedes crear aplicaciones mucho más rápidas y responsivas, mejorando radicalmente la experiencia del usuario.
Capítulo 10: El Proyecto Final: El Hotel Pokémon de Lujo
El Reto del Guardián Definitivo: Construye una Arena para Mewtwo, el Pokémon Genético
Has llegado al final. Tu prueba definitiva es construir un sistema tan complejo, seguro y robusto que sea capaz de gestionar al Pokémon más poderoso: Mewtwo. Debes crear la funcionalidad para asignarle una "Suite de Contención" de lujo en el "Snorlax Sanctuary".
Caso de Uso (La Misión):
Crea las entidades Room y Booking. Una Booking debe tener una relación con un Trainer y una Room, además de fechas de inicio y fin.
Implementa un endpoint POST /bookings.
Este endpoint debe ser seguro (solo para entrenadores autenticados).
Debe validar que la habitación solicitada exista y no esté ya reservada para las fechas solicitadas.
Si la validación falla, debe devolver un error 400 manejado profesionalmente.
Si tiene éxito, debe crear la reserva y devolver un 201 Created.
Asegúrate de que el servicio que gestiona la lógica de reserva esté cubierto por pruebas de integración.
Criterios de Victoria (Objetivos de Aprendizaje):
Un usuario no autenticado no puede hacer una reserva.
Un usuario autenticado puede reservar una habitación disponible.
Intentar reservar una habitación ya ocupada en las mismas fechas devuelve un error claro.
Todo el flujo está documentado en Swagger.
Recompensa (Conocimiento Adquirido): ¡Has construido la arena para Mewtwo! Has demostrado la Maestría Total. Has integrado todos los conocimientos del curso (persistencia, seguridad, validación, testing, etc.) para resolver un problema complejo del mundo real. Has forjado tu Legado del Desarrollador.
documentationImprovements or additions to documentation
1 participant
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Al final de cada capítulo se presenta un reto gamificado, simbolizado por un “Guardián Pokémon”. Estos desafíos buscan reforzar lo aprendido y convertir el recorrido en una experiencia más significativa y memorable.
A continuación se muestra la estructura de retos correspondiente a cada capítulo, diseñada para integrarse de manera natural en la narrativa del curso “El Legado del Desarrollador”.
Nota: Este es un documento vivo. A medida que se complete el código, se agregarán los documentos de referencia con las soluciones correspondientes.
Los retos se presentan en formato narrativo y ofrecen solo los detalles esenciales de implementación siguiendo el modelo MVC tradicional.
No obstante, las soluciones de código se desarrollarán bajo los principios de Screaming Architecture y Arquitectura Hexagonal, que considero una forma más sólida y escalable de estructurar el proyecto.
Para mantener la claridad, los ejemplos se mostrarán utilizando el paquete base
com.legacy, con la idea de que posteriormente puedan refactorizarse siguiendo las prácticas arquitectónicas mencionadas.Capítulo 1: La Aldea Inicial y el Kit del Entrenador
El Reto del Guardián: Derrota a Graveler, el Pokémon Cimiento
Has recibido tu kit de inicio, pero para poder salir de la "Aldea Paleta", debes demostrar que puedes construir una base sólida. Graveler, un Pokémon hecho de roca pura, bloquea el camino. No puedes vencerlo con fuerza, sino con estructura. Debes construir un refugio (tu proyecto) que resista su primer envite.
Spring WebyKotlin.com.legacy.controller.WelcomeControlleranotada como@RestController.@GetMapping("/challenge/start")que devuelva un objeto simple (unadata classde Kotlin) con un mensaje:{"message": "Mi viaje ha comenzado"}.http://localhost:8080/challenge/starten tu navegador o Postman, recibes el JSON de bienvenida, si no existe aún tu reto es completar el código.Referencias:
Capítulo 2: El Primer Hechizo y el Gremio de Controladores
El Reto del Guardián: Supera a Kadabra, el Pokémon Psíquico
Para ser aceptado en el "Gremio de Controladores", debes demostrar que puedes separar la lógica (el poder psíquico) de la presentación. Kadabra te reta a un duelo mental. Debes crear un sistema donde la lógica de negocio esté separada del controlador que la invoca.
com.legacy.service.PokedexServiceanotada con@Component. Esta clase tendrá una funciónfindPokemonById(id: Int)que devuelve el nombre de un Pokémon usando unwhen(ej: si id es 1, devuelve "Bulbasaur"; si es 4, "Charmander". Para cualquier otro, "Pokémon no encontrado").WelcomeController, inyecta elPokedexServiceusando@Autowired.@GetMapping("/pokedex/{id}")que llame al método del servicio y devuelva el nombre del Pokémon./pokedex/4, recibes la cadena "Charmander"./pokedex/99, recibes "Pokémon no encontrado".Capítulo 3: Las Minas de Datos de Ciudad Plateada
El Reto del Guardián: Captura a Onix, el Pokémon Serpiente Roca
En las profundidades de las minas, te encuentras con Onix, una criatura colosal hecha de datos entrelazados. Para capturarlo, debes crear una estructura capaz de almacenar y gestionar su información.
Spring Data JPAyH2 Database.com.legacy.modely define una@EntityTrainercon unid(Long) y unname(String).com.legacy.repositoryy define una interfazTrainerRepositoryque extienda deJpaRepository.TrainerControllercon endpoints para:POST /trainers: Crear un nuevo entrenador.GET /trainers: Listar todos los entrenadores.{"name": "Ash"}.Capítulo 4: El Dojo de la Validación y el Manejo de Errores
El Reto del Guardián: Resiste el ataque de Machoke, el Pokémon Superpoder
En el dojo, Machoke te ataca con una ráfaga de "datos inválidos". Tu API debe ser lo suficientemente fuerte y disciplinada para bloquear estos ataques y responder con elegancia, en lugar de romperse.
Spring Boot Starter Validation.Trainer, añade la anotación@NotBlankal camponame.POST /trainersde tuTrainerController, añade la anotación@Validal cuerpo de la petición.@ControllerAdviceglobal que capture laMethodArgumentNotValidExceptiony devuelva un estado400 Bad Requestcon un mensaje de error claro y personalizado en formato JSON.POST /trainerscon{"name": ""}o{"name": null}ya no causa un error 500, sino que devuelve un código 400.Capítulo 5: La Fortaleza de la Seguridad y el Guardián JWT
El Reto del Guardián: Gánate la lealtad de Arcanine, el Pokémon Legendario
La fortaleza está protegida por el noble Arcanine. No te dejará pasar a menos que le demuestres que eres digno de confianza, presentándole una credencial secreta (un Token JWT).
Spring Securityy una librería para JWT (ej.jjwt).POST /login.POST /loginque, para un usuario y contraseña fijos, genere y devuelva un Token JWT.GET /trainers. Ahora solo debería ser accesible si se proporciona un Token JWT válido en la cabeceraAuthorization: Bearer <token>.GET /trainerssin token devuelve un error 401 o 403./login, usarlo en la cabecera deGET /trainerspermite el acceso.Capítulo 6: El Oráculo de las Pruebas en la Torre Pokémon
El Reto del Guardián: Engaña a Ditto, el Pokémon Transformación
El Oráculo te presenta a Ditto, un ser que puede transformarse en cualquier parte de tu código para poner a prueba su resistencia. Para vencerlo, debes anticipar sus movimientos y crear pruebas que cubran todas sus formas.
PokedexService(del Capítulo 2). UsaAssertionsde JUnit para verificar quefindPokemonById(1)realmente devuelve "Bulbasaur".TrainerController. Usa@SpringBootTestyMockMvcpara simular una llamadaPOST /trainersy verificar que la respuesta sea un201 Created.Capítulo 7: El Mapa del Merodeador: Documentando con Swagger
El Reto del Guardián: Interpreta la visión de Xatu, el Pokémon Místico
Xatu puede ver el pasado y el futuro de tu código, pero solo se comunica a través de visiones crípticas. Tu misión es usar el poder de OpenAPI para traducir esas visiones en un mapa claro y comprensible para todos los viajeros (desarrolladores).
springdoc-openapi-starter-webmvc-ui.TrainerController, usa la anotación@Operation(summary = "Crea un nuevo Entrenador")en el endpointPOST /trainers.@ApiResponsepara documentar la respuesta201 Createdy la400 Bad Requestpor validación./swagger-ui.html.Capítulo 8: El Lanzamiento del Poké Ball: Despliegue y Monitoreo
El Reto del Guardián: Atrapa a Gengar, el Pokémon Sombra
Has desplegado tu aplicación, pero un travieso Gengar se esconde en las "sombras" de tu entorno de producción. Puede causar problemas si no lo vigilas. Debes usar herramientas de monitoreo para exponerlo y mantenerlo bajo control.
Spring Boot Starter Actuator.application.propertiesque se expongan los endpoints dehealtheinfo(management.endpoints.web.exposure.include=health,info)../gradlew bootJar).java -jar ...).http://localhost:8080/actuator/healthy ver el estado{"status":"UP"}.Capítulo 9: La Liga de los Maestros: Temas Avanzados
El Reto del Guardián: Domestica a Jolteon, el Pokémon Relámpago
Para ser un maestro, debes controlar la velocidad del rayo. Jolteon te reta a una carrera. No puedes ganarle en una carrera lineal; debes aprender a hacer varias cosas a la vez, usando el poder de la asincronía.
@EnableAsync.NotificationServicecon un método@AsyncllamadosendWelcomeMessage(trainerName: String). Este método simulará un proceso lento (ej.Thread.sleep(3000)) y luego imprimirá en consola "Mensaje de bienvenida enviado a [trainerName]".POST /trainersjusto después de guardar al nuevo entrenador.Capítulo 10: El Proyecto Final: El Hotel Pokémon de Lujo
El Reto del Guardián Definitivo: Construye una Arena para Mewtwo, el Pokémon Genético
Has llegado al final. Tu prueba definitiva es construir un sistema tan complejo, seguro y robusto que sea capaz de gestionar al Pokémon más poderoso: Mewtwo. Debes crear la funcionalidad para asignarle una "Suite de Contención" de lujo en el "Snorlax Sanctuary".
RoomyBooking. UnaBookingdebe tener una relación con unTrainery unaRoom, además de fechas de inicio y fin.POST /bookings.201 Created.Beta Was this translation helpful? Give feedback.
All reactions