# Fundamento 2. Vocabulario

## Diseñar el vocabulario

Un nombre no decora una solución terminada. Decide qué concepto verá el consumidor y qué podrá esperar de él.

Cuando una API usa palabras como `execute`, `data` o `response`, obliga a leer la implementación para descubrir su significado. Cuando nombra una intención, un resultado o una situación reconocible, permite entender el contrato sin abrir la implementación.

El vocabulario de una API debería seguir siendo verdadero aunque cambie su implementación.

Todo valor que cruza una API necesita un significado claro. Normalmente basta con resolver estas preguntas:

- ¿qué representa?;
- ¿qué valores son válidos?;
- ¿cómo se compara?;
- ¿puede estar ausente?;
- ¿quién conserva su estado mutable?;
- ¿qué representación puede observar el consumidor?

La respuesta no siempre requiere un tipo nuevo. Un tipo propio aporta cuando nombra una diferencia, protege una invariante o impide una combinación inválida. Si el contexto ya evita la confusión y las reglas son las mismas, separar dos valores solo añade ceremonia.

## Ejemplo: añadir una tarea a una cola

Esta firma describe principalmente la organización del código:

```text
QueueService.Execute(EnqueueCommand) → QueueResponse
```

No sabemos qué se ejecuta, qué contiene la respuesta ni qué puede salir mal. La misma capacidad puede expresarse así:

```text
Queue.Enqueue(Task) → Position | QueueFull
```

Cada palabra cumple una función:

- `Queue` nombra el módulo y aporta contexto;
- `Enqueue` expresa la intención del consumidor;
- `Task` nombra el valor que entra;
- `Position` explica el resultado;
- `QueueFull` identifica una situación ante la que el consumidor puede actuar.

La implementación puede usar memoria, archivos o un sistema remoto. Ninguna de esas decisiones obliga a cambiar el mensaje.

## Ejemplo en Go

El ejemplo mantiene `Queue`, `Enqueue`, `Task`, `Position` y `QueueFull` como vocabulario visible.

```go
import "errors"

type Task struct{ ID string }
type Position int

var ErrQueueFull = errors.New("queue full")

type Queue interface {
    Enqueue(Task) (Position, error)
}
```

## Nombres exportados

Los nombres públicos son el vocabulario compartido entre un módulo y sus consumidores. Merecen más estabilidad que los identificadores internos porque aparecen en llamadas, documentación, tests y, a veces, datos serializados.

Cada lenguaje expresa esa frontera de otra forma. En Go, un identificador exportado comienza con mayúscula; los nombres con minúscula permanecen dentro del paquete. Un directorio `internal` también permite limitar qué parte del árbol puede importar un paquete.

Exportar no mejora un nombre ni convierte un tipo en una buena abstracción. Primero se identifica qué necesita nombrar el consumidor; después se le da la visibilidad correspondiente. Los helpers y representaciones internas pueden usar palabras más técnicas sin contaminar la conversación pública.

## Buenos nombres

### El módulo

El nombre de un módulo debe indicar la capacidad que reúne, no el patrón con el que fue construido.

`Manager`, `Service`, `Handler`, `Facade` o `Helper` suelen ser débiles cuando aparecen solos. Clasifican una estructura técnica, pero no explican qué ofrece. `QueueManager`, por ejemplo, permite imaginar casi cualquier responsabilidad; `Queue` establece un contexto concreto para mensajes como `Enqueue`, `Next` o `Remove`.

Esto no convierte los nombres técnicos en un error universal. En la composición puede ser útil distinguir `MemoryQueue` de `RemoteQueue`, porque allí el consumidor elige una implementación. La API que ambas proporcionan puede seguir llamándose `Queue`.

La pregunta útil es: ¿el consumidor necesita conocer este mecanismo? Si la respuesta es no, el nombre técnico pertenece al interior.

### Los mensajes

Los mensajes expresan intenciones o hechos, no pasos internos.

Un verbo como `Enqueue` permite anticipar el efecto. `Run`, `Execute`, `Process` o `Handle` solo son precisos cuando ejecutar, procesar o despachar constituye realmente la capacidad del módulo.

La prueba más sencilla consiste en leer el uso como una frase:

```text
position = queue.Enqueue(task)
```

Si para entenderla hay que traducir categorías del framework, el contrato todavía habla desde la implementación.

### Valores y resultados

Un tipo merece nombre cuando representa una diferencia que importa. `Task`, `Position` y `Capacity` dicen más que `Data`, `Item` o `ValueObject`, siempre que esas sean las palabras del contexto real.

Los sufijos que repiten la categoría técnica suelen sobrar:

```text
TaskModel
PositionValueObject
QueueResponseDTO
```

Pueden ser necesarios dentro de un adaptador que traduce dos representaciones, pero no deberían propagarse a la API principal por accidente.

Las unidades también forman parte del significado. `Delay` puede resultar ambiguo si el consumidor necesita distinguir milisegundos de segundos. No siempre hace falta un nombre más largo; sí hace falta conservar la diferencia que evita un uso incorrecto.

### Booleanos, errores y eventos

Un booleano se entiende mejor como una proposición:

```text
queue.IsFull()
queue.Contains(taskID)
```

`Check`, `Flag` o `Status` no aclaran qué significa `true`. Si existen más de dos resultados relevantes, probablemente el contrato necesite un estado nombrado en lugar de un booleano.

Los errores públicos describen situaciones ante las que el consumidor puede reaccionar. `QueueFull` permite esperar o elegir otra cola. `DatabaseError` filtra infraestructura y quizá no ofrece ninguna decisión útil. Los detalles técnicos pueden conservarse como causa interna, log o diagnóstico sin convertirse en vocabulario estable.

Un evento nombra un hecho que ya ocurrió. `TaskQueued` evita confundir la notificación con la petición `EnqueueTask`. El pasado también ayuda a que el nombre siga siendo cierto aunque cambie el transporte.

## Comunicación

El vocabulario funciona como un sistema, no como una lista de términos aislados. Módulo, mensaje, argumentos y resultados deben poder leerse juntos como una conversación.

### El contexto evita repeticiones

La precisión no consiste en incluir toda la explicación en cada identificador:

```text
queue.Enqueue(task)
```

es más claro que:

```text
queueService.ExecuteTaskEnqueueCommand(taskValueObject)
```

En el primer caso, módulo, mensaje y argumento reparten el significado. En el segundo, las categorías técnicas añaden longitud sin explicar mejor el contrato.

Un nombre corto puede ser ambiguo y uno largo puede compensar un contexto mal elegido. La meta es usar las palabras mínimas que conserven el significado donde se leen.

### Encontrar un nombre

El nombre suele aparecer al describir primero la conversación:

1. Escribe una frase desde el consumidor: «quiero añadir esta tarea a la cola».
2. Separa el contexto, la intención, los valores y las situaciones que cambian la conducta.
3. Comprueba qué palabras utilizan las personas que conocen el problema.
4. Lee una llamada completa y elimina lo que el contexto ya dice.
5. Imagina otra implementación y comprueba que el vocabulario sigue siendo cierto.
6. Revisa de nuevo cada error o evento que el consumidor deba distinguir.

Si cuesta nombrar un módulo, puede haber responsabilidades mezcladas o una abstracción prematura. En ese caso conviene volver a la conversación antes de buscar un sinónimo más elegante.

Esta práctica coincide con el lenguaje ubicuo de DDD: los nombres ganan precisión dentro de un contexto explícito, no en un diccionario universal ([*DDD Reference*, Eric Evans](https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf)). API-DD añade una comprobación concreta: el vocabulario debe funcionar desde el módulo consumidor y sobrevivir a implementaciones alternativas.

## Renombrar es migrar

Una vez publicada, una palabra forma parte del contrato. Cambiarla puede romper compilación, mensajes serializados, documentación, métricas o integraciones.

Una migración puede requerir introducir el nombre nuevo junto al anterior, adaptar consumidores y retirar el alias cuando ya no exista dependencia. Que el nombre nuevo sea mejor no vuelve inocuo el cambio.

> **Un buen nombre explica la conversación y no delata el mecanismo que la hace posible.**
