KriaturasBases de datos para quien empieza

Parte III · Diseñar bien

Capítulo 6 — Pensar antes de crear (diseño conceptual)

Hagamos cuentas de lo que llevas construido. En cinco capítulos has creado la tabla jugador, la tabla carta, la tabla mazo, y dos tablas intermedias, coleccion y mazo_carta. Cinco tablas, conectadas entre sí con claves foráneas, hablando unas con otras. Nada mal.

Pero seguro que ya has notado algo: empieza a costar tenerlo todo en la cabeza. ¿La clave foránea iba en mazo o en jugador? ¿coleccion conectaba con qué, exactamente? Cada tabla nueva que añades es una pieza más que tienes que recordar cómo encaja con las demás. Y solo llevas cinco. Imagina el juego dentro de un año, con partidas, amistades, intercambios, logros…

Hasta ahora has trabajado como quien construye una casa poniendo ladrillos sin mirar un plano: vas viendo sobre la marcha. Funciona mientras la casa es pequeña. Pero cualquier estudio que se pone a hacer un videojuego de verdad no empieza programando. Empieza dibujando. En este capítulo vas a hacer lo mismo: parar, dar un paso atrás y dibujar el plano de Kriaturas antes de seguir creando tablas.


El diseño no es teclear: es un proceso

Cuando piensas en "hacer una base de datos", es fácil imaginar a alguien escribiendo CREATE TABLE a toda velocidad. Pero eso es solo el final del camino. Crear una base de datos buena es un proceso: una serie de pasos que van de "tengo una idea para un juego" a "el juego guarda y recupera sus datos sin problemas".

Ese proceso suele dividirse en cinco fases. No hace falta que te las aprendas de memoria; lo importante es entender que cada una resuelve un trozo distinto del problema, y que se hacen en orden.

  1. Requisitos. Entender qué necesita guardar el juego. Aquí no se dibuja ni se programa nada: se escucha y se anota. "Hay jugadores. Cada jugador tiene cartas. Las cartas se agrupan en mazos. Dos jugadores juegan partidas." Son frases en lenguaje normal, como las que te diría quien ha pensado el juego.

  2. Diseño conceptual. Convertir esas frases en un dibujo de alto nivel: qué entidades hay y cómo se relacionan, sin hablar todavía de tablas ni de ningún programa concreto. Es el plano. Esta es la fase de la que trata el capítulo.

  3. Diseño lógico. Traducir el plano a tablas concretas, con sus columnas y sus claves foráneas. Es justo lo que has estado haciendo a mano en los capítulos 2 a 5; más adelante lo harás a partir del plano, que es la forma ordenada.

  4. Diseño físico. Decidir cómo se guarda todo por dentro para que vaya rápido: índices y cosas así. Lo verás de forma intuitiva en el capítulo 14.

  5. Implementación y puesta a punto. Crear la base de datos de verdad, cargar los datos y afinar el rendimiento con el juego ya funcionando.

La gracia de partir el trabajo en fases es la misma que la de partir un juego en niveles: cada fase es un problema manejable en vez de un monstruo enorme. Y fíjate en algo: las fases 1, 2 y 3 son donde se decide si tu base de datos va a ser buena o un quebradero de cabeza. Las fases 4 y 5 son importantes, pero llegan después y las tocaremos de pasada. Este libro vive sobre todo en las tres primeras.

Nota rápida sobre la fase 3. Cuando en el capítulo 2 escribías CREATE TABLE jugador (...), estabas haciendo diseño lógico sin saberlo, y saltándote la fase 2. Para una tabla suelta no pasa nada. Para un juego entero, saltarse el plano es justo lo que vamos a dejar de hacer.

El plano: entidades, relaciones y multiplicidades

Vamos al corazón del capítulo. El plano de una base de datos tiene un nombre técnico: modelo conceptual. Es un dibujo de la base de datos antes de que exista. Muestra tres cosas, y solo tres, todas conocidas tuyas:

  • las entidades (las "cosas" del juego),
  • los atributos de cada entidad (lo que sabes de ella),
  • y las relaciones entre entidades (cómo se conectan).

Lo que no muestra es igual de importante: no habla de tablas, ni de claves foráneas, ni de SQL, ni de ningún programa concreto. Es deliberadamente abstracto. Estás dibujando qué hay en tu juego, no cómo se guardará. Esa separación es lo que hace al plano tan útil: puedes pensar el juego sin pelearte aún con los detalles técnicos.

La forma más usada de dibujar este plano es el modelo entidad-relación, o modelo ER para los amigos. Es popular justamente porque es sencillo: cajas para las entidades, líneas para las relaciones, y unas anotaciones en los extremos de las líneas. Nada más. (Existe otra notación llamada UML, muy parecida; no necesitas distinguirlas todavía.)

Las cajas: entidades

Una entidad ya sabes lo que es desde el capítulo 2: una "cosa" del juego con identidad propia, que puedes distinguir de las demás. El jugador. La carta. El mazo. En el diagrama, cada entidad es una caja con su nombre, y dentro o al lado apuntas sus atributos principales.

┌──────────────┐
│   jugador    │
├──────────────┤
│ id (clave)   │
│ alias        │
│ email        │
│ fecha_alta   │
└──────────────┘

Subrayamos o marcamos la clave primaria, porque es el atributo que identifica cada caso sin ambigüedad (lo viste en el capítulo 2). El resto son atributos normales.

Las líneas: relaciones

Una relación es una asociación entre dos entidades: un verbo que las conecta. Un jugador tiene mazos. Un jugador posee cartas. Un mazo contiene cartas. En el diagrama, cada relación es una línea entre dos cajas, y encima escribes ese verbo para que se lea de corrido.

┌──────────┐   tiene   ┌──────────┐
│ jugador  │───────────│   mazo   │
└──────────┘           └──────────┘

Esa línea no es decoración: es exactamente lo que en los capítulos anteriores acabó siendo una clave foránea (en el 1:N) o una tabla intermedia (en el N:M). Pero ahora, en el plano, todavía no decides cómo se implementa. Solo dices que la conexión existe. El "cómo" viene después, en el diseño lógico.

Las anotaciones: multiplicidad

Aquí está la parte nueva e importante. Una línea, por sí sola, te dice que hay una conexión, pero no de qué tipo. ¿Un jugador tiene un mazo o muchos? ¿Una carta la posee un solo jugador o varios? Esa información se llama multiplicidad (también la verás como cardinalidad), y es la forma formal de decir lo que ya conoces como 1:N o N:M.

La multiplicidad se anota en cada extremo de la línea, y responde a una pregunta muy concreta: "fijada una fila de este lado, ¿con cuántas del otro lado puede ir?". Vamos con el ejemplo de los mazos:

  • En el extremo del jugador escribimos 1: cada mazo pertenece a un solo jugador.
  • En el extremo del mazo escribimos N (o "muchos"): cada jugador puede tener muchos mazos.
┌──────────┐ 1   tiene   N ┌──────────┐
│ jugador  │───────────────│   mazo   │
└──────────┘               └──────────┘

Léelo en los dos sentidos, que es el truco para no equivocarse: "un jugador tiene muchos mazos" y "un mazo es de un jugador". Las dos frases tienen que ser verdad. Esto es exactamente la relación 1:N del capítulo 4, ahora dibujada.

Y la colección, que en el capítulo 5 descubriste que era muchos a muchos, se anota con N y M en los extremos:

┌──────────┐ N   posee   M ┌──────────┐
│ jugador  │───────────────│  carta   │
└──────────┘               └──────────┘

"Un jugador posee muchas cartas" y "una carta la poseen muchos jugadores". Las dos verdad, las dos a la vez: N:M. Las letras N y M solo significan "muchos" y "muchos otros"; se usan dos letras distintas para dejar claro que los dos lados son independientes.

Existe también la multiplicidad 1:1 (uno a uno): una fila de aquí va con como mucho una de allá, y al revés. Es la menos común. Un ejemplo sería separar los datos de acceso de un jugador (contraseña, último login) en una entidad aparte conectada 1:1 con jugador. No la necesitamos en Kriaturas por ahora, pero ya sabes que existe.

El plano de Kriaturas, por fin

Tienes todas las piezas. Vamos a juntar en un solo dibujo las cinco tablas que has construido y verlas como lo que son: el modelo conceptual de Kriaturas hasta este punto del libro.

Repasemos las entidades y sus relaciones antes de dibujar:

  • jugador y mazo, conectadas por tiene (1:N): un jugador tiene muchos mazos.
  • jugador y carta, conectadas por posee (N:M): la colección.
  • mazo y carta, conectadas por contiene (N:M): las cartas de cada mazo.

Aquí está el plano en cajas y líneas:

                       ┌──────────┐
                       │  carta   │
                       │  id      │
                       │  nombre  │
                       │  rareza  │
                       │  coste   │
                       └──────────┘
                        N │      │ M
              posee ──────┘      └────── contiene
                    │                  │
                  M │                  │ N
            ┌──────────┐ 1   tiene   N ┌──────────┐
            │ jugador  │───────────────│   mazo   │
            │  id      │               │  id      │
            │  alias   │               │  nombre  │
            │  email   │               └──────────┘
            │ fecha_   │
            │  alta    │
            └──────────┘

Léelo despacio, recorriendo las tres líneas:

  • jugador — tiene — mazo: 1 a N. Un jugador, muchos mazos.
  • jugador — posee — carta: N a M. La colección, muchos a muchos.
  • mazo — contiene — carta: N a M. Las cartas del mazo, muchos a muchos.

Tres entidades, tres relaciones, y de un vistazo entiendes todo el modelo. Eso es lo que te daba el plano y lo que no te daba la lista de tablas suelta en la cabeza.

Si vas a publicar tu diagrama en la web o en un repositorio, hay una forma de escribirlo en texto que muchas herramientas convierten en un dibujo de verdad, con sus cajas bien hechas. Se llama Mermaid, y el mismo modelo se ve así:

No te preocupes por la sintaxis exacta de los símbolos; lo importante es que el dibujo dice lo mismo que el de cajas: una línea por relación y la multiplicidad en cada extremo. Usa la forma que te resulte más cómoda; las dos son el mismo plano.

Del plano a las tablas (un vistazo adelante). Quizá te preguntes dónde quedaron coleccion y mazo_carta, que tanto trabajo costaron en el capítulo 5. Buena observación: no salen en el plano conceptual. Esas dos tablas intermedias no son entidades de tu juego; son el truco técnico con el que se implementa una relación N:M cuando bajas al diseño lógico. En el plano, una N:M es solo una línea con N y M en los extremos. Las tablas intermedias aparecen al traducir esa línea a tablas, que es la fase siguiente. Esto es justo la diferencia entre qué hay (plano) y cómo se guarda (tablas).

Resumen

Has subido un escalón. Hasta ahora construías tablas con las manos; ahora sabes pensar y dibujar antes de teclear. Crear una base de datos es un proceso de cinco fases —requisitos, diseño conceptual, diseño lógico, diseño físico, implementación— y el libro vive sobre todo en las tres primeras. El modelo conceptual es el plano: un dibujo de entidades (cajas), relaciones (líneas con un verbo) y multiplicidades (las anotaciones 1, N, M en los extremos que dicen si la conexión es 1:N o N:M). Lo dibujaste para Kriaturas: jugador tiene mazo (1:N), jugador posee carta (N:M) y mazo contiene carta (N:M). Y aprendiste a leer la multiplicidad preguntando en los dos sentidos, que es el método infalible para no equivocarte.

El plano que has dibujado tiene, sin embargo, una mentira piadosa. Todas las cartas están metidas en la misma caja, como si fueran iguales. Pero en Kriaturas una criatura tiene ataque, defensa y vida; un objeto se gasta o no se gasta; un entrenamiento dura unos turnos. Son cartas, sí, pero distintas. ¿Cómo dibujas en el plano algo que "es una carta, pero de un tipo especial con sus propios datos"? De eso va el siguiente capítulo: las familias de cartas.