# Fundamento 4. Autonomía

## Autonomía en cada escala

La autonomía no aparece únicamente en el módulo más grande. Puede fomentarse de forma granular cada vez que la perspectiva de API-DD se aplica recursivamente.

| Escala | Qué significa autonomía |
|---|---|
| Módulo | Reúne la capacidad y protege sus invariantes |
| API | Ofrece una conversación suficiente sin revelar cómo se coordina el interior |
| Mensaje de resultado | Tiene significado propio y no comparte estado mutable con quien lo produjo |

Autonomía no significa aislamiento. Un módulo puede consumir otras APIs y un resultado puede contener varios valores. La diferencia es que cada elemento conserva un límite claro: ningún consumidor necesita reparar su estado, completar su significado ni conocer una representación ajena.

Aplicar el fundamento a un resultado no lo convierte en otro módulo. El resultado sigue siendo vocabulario de la API, pero también necesita propiedad y validez propias.

## API autónoma

Una API es autónoma cuando el consumidor puede expresar una intención y comprender la respuesta dentro de la misma conversación. No necesita abrir la implementación, consultar una estructura interna ni coordinar colaboradores que pertenecen al proveedor.

Una secuencia pública puede formar parte de un protocolo real. Pierde autonomía cuando sus pasos solo existen para terminar de montar el módulo:

```text
value := Interval{}
value.SetStart(2)
value.SetEnd(8)
value.Validate()
```

La intención completa puede expresarse en un solo mensaje:

```text
Interval.New(2, 8) → Interval | InvalidInterval
```

La autonomía tampoco exige que cada respuesta incluya todos los datos imaginables. Incluye lo necesario para que el consumidor actúe ante las diferencias que el contrato reconoce.

## Módulo completo

Un módulo es completo cuando reúne lo necesario para cumplir el contrato que ofrece. El consumidor usa su capacidad mediante la API sin completar pasos internos, corregir su estado ni decidir cómo deben coordinarse sus dependencias.

Completo no significa autosuficiente. El módulo puede leer, calcular o producir efectos mediante otras APIs. Su responsabilidad consiste en gobernar esas colaboraciones y traducirlas al contrato que ofrece.

Una señal de incompletitud aparece cuando varios consumidores repiten la misma coordinación para obtener una capacidad que debería pertenecer al módulo. La solución no es esconder cualquier secuencia: es asignar la responsabilidad al límite que puede garantizarla.

## Módulo válido

Un módulo válido conserva sus invariantes en todos los estados observables. Puede rechazar una entrada o devolver un error; evita continuar con un estado incoherente que otro consumidor tenga que descubrir después.

La validez se protege donde entra información:

- construcción;
- mensajes que cambian estado;
- interpretación de datos externos;
- recuperación desde persistencia;
- resultados recibidos desde otra API.

Un estado inicial vacío puede ser válido. También puede ser inválido pero seguro. La API debe distinguirlo antes de producir un efecto incorrecto.

## Resultados autónomos

Un resultado autónomo pertenece a la conversación que lo recibe. Su significado está completo y su contenido no cambia porque el proveedor continúe trabajando ni porque otro consumidor lo utilice.

Esto requiere evitar referencias compartidas a estado mutable. Devolver directamente un slice, un mapa o un puntero interno permite que el consumidor modifique al proveedor y que el proveedor altere un resultado ya entregado. Ambos dejan de ser autónomos.

Las alternativas habituales son:

- devolver valores con semántica de copia;
- usar campos privados y operaciones de lectura;
- copiar colecciones al entregar y al exponer su contenido;
- transferir la propiedad de forma explícita;
- ofrecer otra API para recorrer datos cuando una copia resulte demasiado costosa.

Go no tiene una declaración general de inmutabilidad. Aquí, inmutable significa que la API pública no permite cambiar el resultado y que el proveedor no puede alterarlo después de entregarlo. Un struct copiado puede contener slices, mapas o punteros que aún comparten memoria; la autonomía debe llegar hasta cada referencia mutable, no detenerse en el tipo exterior.

## Ejemplo en Go

`Collection` conserva su estado y entrega un `Snapshot` autónomo. El snapshot copia los datos y solo ofrece operaciones de lectura.

```go
package collection

import "errors"

var (
    ErrInvalidLimit = errors.New("invalid limit")
    ErrInvalid      = errors.New("invalid collection")
    ErrFull         = errors.New("collection full")
)

type Snapshot struct {
    values []string
}

func newSnapshot(values []string) Snapshot {
    return Snapshot{values: clone(values)}
}

func (s Snapshot) Len() int {
    return len(s.values)
}

func (s Snapshot) At(index int) (string, bool) {
    if index < 0 || index >= len(s.values) {
        return "", false
    }
    return s.values[index], true
}

type Collection struct {
    limit  int
    values []string
}

func New(limit int) (*Collection, error) {
    if limit <= 0 {
        return nil, ErrInvalidLimit
    }
    return &Collection{limit: limit}, nil
}

func (c *Collection) Add(value string) error {
    if c == nil || c.limit <= 0 {
        return ErrInvalid
    }
    if len(c.values) == c.limit {
        return ErrFull
    }
    c.values = append(c.values, value)
    return nil
}

func (c *Collection) Snapshot() Snapshot {
    if c == nil {
        return Snapshot{}
    }
    return newSnapshot(c.values)
}

func clone(values []string) []string {
    return append([]string(nil), values...)
}
```

`New` produce un módulo válido o un error. `Add` responde de forma segura incluso ante el valor cero de Go. `Snapshot` no conserva el slice de `Collection` ni lo expone: `Len` y `At` permiten leerlo sin ofrecer una operación de mutación.

## Valores iniciales y ausencia

En Go, todo tipo concreto tiene un valor cero. Publicar `New` no lo elimina. El contrato puede tratarlo como útil, como ausencia o como inválido pero seguro. La [especificación de Go](https://go.dev/ref/spec#The_zero_value) define el mecanismo; la API define su significado.

Ausente y presente con valor cero tampoco son siempre equivalentes. Si la diferencia cambia el comportamiento, puede representarse mediante `(T, bool)`, un puntero o un resultado nombrado. Los formatos de transporte se traducen en el adaptador para que el módulo reciba significado, no detalles de serialización.

## Dependencias autónomas

Una dependencia forma parte de la construcción cuando el módulo no puede cumplir su contrato sin ella. Recibirla mediante una API hace visible qué necesita, pero no traslada su coordinación al consumidor.

No hace falta introducir una interfaz para cada helper. Una dependencia merece contrato propio cuando tiene otros consumidores o proveedores, cruza un límite relevante o evoluciona de forma autónoma. En ese punto los mismos fundamentos pueden aplicarse de nuevo.

## Revisión práctica

1. La API expresa una intención completa para su consumidor.
2. El módulo gobierna sus dependencias y conserva sus invariantes.
3. La creación produce un módulo válido o un fallo explícito.
4. Cada resultado contiene el significado necesario para actuar.
5. Ningún resultado comparte estado mutable con el proveedor.
6. Slices, mapas, punteros y elementos internos tienen propiedad clara.
7. La misma revisión se repite en cada límite granular relevante.

> **La autonomía se conserva desde el módulo hasta el resultado que cruza su API.**
