Ir al contenido

Taller: acordar el modelo consolidado del proyecto

Al terminar este taller tu equipo va a ser capaz de:

  • Consolidar los modelos de dominio de todos los módulos en un solo diagrama de clases UML.
  • Definir cada asociación inter-módulo: qué clase de qué módulo se relaciona con cuál, en qué dirección y con qué cardinalidad.
  • Precisar cada asociación en una tabla: qué anotación lleva cada extremo (@OneToMany, @ManyToOne, @ManyToMany u @OneToOne) y cómo se llama el atributo mappedBy del lado inverso, y quién es el responsable de escribirla.
  • Publicar el resultado en la wiki del repositorio del grupo y aprobarlo entre todos antes de escribir una línea de JPA.

Este taller no escribe código. Produce el diagrama y la tabla que el Paso 1 del Release 6 pide como primer paso, y que vas a necesitar al mapear las relaciones en los siguientes tutoriales.

Antes de empezar, ten a mano:

  • El modelo de dominio de tu módulo en UML (diagrama de clases), con sus atributos y las relaciones intra-módulo que ya tiene: las que venían del Release 2.
  • La teoría de Persistencia con JPA (2): mapeo de asociaciones, que explica las cardinalidades y quién es el propietario de una asociación.

2. Paso 1: cada integrante trae el modelo de su módulo

Sección titulada «2. Paso 1: cada integrante trae el modelo de su módulo»

Cada integrante lleva su diagrama de clases UML, con los atributos de sus entidades y las relaciones intra-módulo (las que ya existen entre las entidades de su propio módulo).

Antes de seguir, revisen que:

  • Todos usan la misma notación para la cardinalidad (1, 0..1, 1..*, *).
  • Los nombres de las clases coinciden con los de los DTO del proyecto (ArtistaDTO pasa a ArtistaEntity, como pide el Release 6).
  • Cada relación tiene su dirección clara: qué clase conoce a cuál.

3. Paso 2: consolidar el diagrama y definir las asociaciones inter-módulo

Sección titulada «3. Paso 2: consolidar el diagrama y definir las asociaciones inter-módulo»

El equipo junta los modelos de todos los módulos en un solo diagrama de clases UML del proyecto completo. Ahí se definen las asociaciones inter-módulo, es decir, las que cruzan de un módulo a otro.

Por cada una, el equipo responde estas preguntas:

Pregunta Qué se decide
¿Qué clase de qué módulo se relaciona con cuál? Las dos clases involucradas
¿En qué dirección? Si solo una clase conoce a la otra (unidireccional) o si se conocen mutuamente (bidireccional)
¿Con qué cardinalidad? Uno a uno, uno a muchos o muchos a muchos

El diagrama dice qué se relaciona con qué. La tabla dice cómo se modela esa relación en los objetos Java: qué anotación lleva cada extremo y cómo se llama el atributo mappedBy. No se habla todavía de llaves foráneas ni de tablas: eso lo decide JPA a partir de las anotaciones, no al revés. El equipo completa una fila por cada asociación inter-módulo:

Campo Qué se escribe
Clases involucradas Las dos clases, con su módulo
Cardinalidad 1 a 1, 1 a N o N a N
Dirección Unidireccional (de cuál a cuál) o bidireccional
Extremo propietario Clase, nombre del atributo y anotación (sin mappedBy)
Extremo inverso Clase, nombre del atributo y anotación, con mappedBy igual al nombre exacto del atributo del extremo propietario
Responsable El nombre de un integrante por asociación: quien escribe el extremo propietario, el que tiene esa entidad en su módulo

El responsable evita que una relación entre dos módulos se quede sin escribir porque cada uno cree que le toca al otro. El integrante del extremo inverso agrega su lado en su propio PR, así que su nombre no hace falta en la tabla: se deduce de su módulo.

Un ejemplo con las entidades de los tutoriales (las filas del tuyo salen de tu propio diagrama; Ana y Luis son nombres de ejemplo):

Clases Cardinalidad Dirección Extremo propietario Extremo inverso Responsable
ArtistaEntity y AlbumEntity N a N Bidireccional En ArtistaEntity: private List<AlbumEntity> albumes; anotado @ManyToMany En AlbumEntity: private List<ArtistaEntity> artistas; anotado @ManyToMany(mappedBy = "albumes") Ana
AlbumEntity y CancionEntity 1 a N Bidireccional En CancionEntity: private AlbumEntity album; anotado @ManyToOne En AlbumEntity: private List<CancionEntity> canciones; anotado @OneToMany(mappedBy = "album") Luis

Cómo decidir el extremo propietario y el nombre de mappedBy

Sección titulada «Cómo decidir el extremo propietario y el nombre de mappedBy»

En toda asociación bidireccional, un extremo es el propietario (su anotación no lleva mappedBy) y el otro es el inverso (su anotación lleva mappedBy = "...", con el nombre exacto del atributo declarado en el propietario). La teoría lo explica en detalle; qué extremo elegir depende de la cardinalidad:

  • Uno a muchos: el propietario es siempre el lado “muchos”, el que lleva @ManyToOne. El lado “uno” lleva @OneToMany(mappedBy = "..."). En el ejemplo, CancionEntity es el propietario y AlbumEntity usa mappedBy = "album", el nombre del atributo en CancionEntity.
  • Muchos a muchos: ambos extremos llevan @ManyToMany. Ninguno es “naturalmente” propietario: es una convención. El equipo elige uno y todos usan el mismo lado. Elegir distinto en cada módulo es justo el conflicto que este taller evita.
  • Uno a uno: ambos extremos llevan @OneToOne. También se elige un lado como propietario.

Dos cosas quedan registradas en la wiki del repositorio del grupo:

  1. El diagrama de clases consolidado.
  2. La tabla de asociaciones.

Descarga la plantilla de la tabla (Markdown) y copia su contenido en una página nueva de la wiki: ya trae las columnas y un ejemplo de fila para que el equipo complete una fila por cada asociación inter-módulo.

Nadie empieza la implementación hasta que estén aprobados por todos los integrantes. Las entidades con asociaciones inter-módulo se escriben después de esa aprobación, y siguen exactamente lo acordado: cardinalidad, dirección, extremo propietario y nombre de mappedBy no se vuelven a discutir al escribir el código.

IA permitida aquí: una vez que el equipo tiene el diagrama de clases UML consolidado, puede pedirle a Gemini que proponga la tabla de asociaciones: qué anotación lleva cada extremo, cuál es el propietario y qué nombre debería tener el atributo mappedBy del lado inverso. El equipo revisa cada cardinalidad y cada dirección antes de aprobar: es exactamente el tipo de decisión que un modelo mal traducido deja pasar sin que nada truene, hasta que dos módulos entran en conflicto al compilar. La IA propone la tabla; el equipo decide y firma.


  • Modelar las asociaciones inter-módulo por separado. Cada integrante dibuja su lado y no se comparan: las anotaciones y los nombres de atributo no coinciden.
  • Dejar la dirección sin decidir. “Se relacionan” no alcanza: sin dirección no se sabe qué clase declara el atributo.
  • Elegir distinto extremo propietario en cada módulo para una relación muchos a muchos.
  • Escribir un mappedBy que no coincide exactamente con el nombre del atributo del propietario. Es un error fácil de cometer si el nombre no quedó acordado por escrito.
  • Empezar a escribir JPA antes de la aprobación. Cambiar el modelo después obliga a rehacer entidades, repositories y datos iniciales.

Antes de dar el taller por terminado, el equipo revisa esta lista:

  • El diagrama de clases consolidado incluye los módulos de todos los integrantes.
  • Cada asociación inter-módulo tiene clases, cardinalidad y dirección.
  • Cada asociación tiene su fila en la tabla, con la anotación de cada extremo, el nombre exacto del atributo mappedBy en el lado inverso y el nombre de su responsable.
  • El diagrama y la tabla están publicados en la wiki del repositorio.
  • Todos los integrantes leyeron el resultado completo y lo aprobaron.

Con eso aprobado, cada integrante puede escribir las relaciones de su módulo: empieza por el tutorial de @OneToMany y sigue con el de @ManyToMany.