# Foundation 4. Autonomy

## Autonomy at each scale

Autonomy does not only appear in the largest module. It can be fostered on a granular basis whenever the API-DD perspective is applied recursively.

| Scale | What does autonomy mean |
|---|---|
| Module | Gather capacity and protect its invariants |
| API | Offers enough conversation without revealing how the interior is coordinated |
| Result message | It has its own meaning and does not share a mutable state with the person who produced it |

Autonomy does not mean isolation. A module can consume other APIs and a result can contain multiple values. The difference is that each element retains a clear limit: no consumer needs to repair its state, complete its meaning, or learn about a foreign representation.

Applying the rationale to a result does not turn it into another module. The result is still API vocabulary, but it also needs its own ownership and validity.

##Standalone API

An API is autonomous when the consumer can express an intent and understand the response within the same conversation. You do not need to open the implementation, refer to an internal structure, or coordinate collaborators who belong to the provider.

A public sequence can be part of a real protocol. You lose autonomy when your steps only exist to finish assembling the module:

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

The entire intent can be expressed in a single message:

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

Autonomy also does not require that every response include every imaginable piece of data. It includes what is necessary for the consumer to act on the differences that the contract recognizes.

## Complete module

A module is complete when it brings together what is necessary to fulfill the contract it offers. The consumer uses its capability through the API without completing internal steps, correcting its state, or deciding how its dependencies should be coordinated.

Complete does not mean self-sufficient. The module can read, calculate or produce effects through other APIs. Your responsibility is to govern those collaborations and translate them into the contract you offer.

An incompleteness signal appears when several consumers repeat the same coordination to obtain a capacity that should belong to the module. The solution is not to hide any sequence: it is to assign responsibility to the limit that can guarantee it.

## Valid module

A valid module preserves its invariants in all observable states. It can reject input or return an error; avoids continuing with an inconsistent state that another consumer has to discover later.

Validity is protected where information enters:

- construction;
- messages that change status;
- interpretation of external data;
- recovery from persistence;
- results received from another API.

An empty initial state may be valid. It can also be invalid but safe. The API must distinguish this before producing the wrong effect.

## Autonomous results

An autonomous result belongs to the conversation that receives it. Its meaning is complete and its content does not change because the provider continues to work or because another consumer uses it.

This requires avoiding shared references to mutable state. Directly returning a slice, map, or internal pointer allows the consumer to modify the provider and the provider to alter an already delivered result. Both are no longer autonomous.

The usual alternatives are:

- return values ​​with copy semantics;
- use private fields and read operations;
- copy collections when delivering and exposing their content;
- transfer ownership explicitly;
- offer another API to traverse data when a copy is too expensive.

Go does not have a general statement of immutability. Here, immutable means that the public API does not allow changing the result and that the provider cannot alter it after delivering it. A copied struct may contain slices, maps, or pointers that still share memory; autonomy must reach each mutable reference, not stop at the external type.

## Example in Go

`Collection` retains its state and returns a stand-alone `Snapshot`. The snapshot copies the data and only offers read operations.

```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` produces a valid module or an error. `Add` responds safely even to the zero value of Go. `Snapshot` does not preserve the `Collection` slice or expose it: `Len` and `At` allow it to be read without offering a mutation operation.

## Initial values ​​and absence

In Go, every concrete type has a value of zero. Posting `New` does not remove it. The contract may treat it as useful, as absent, or as invalid but safe. The [Go specification](https://go.dev/ref/spec#The_zero_value) defines the mechanism; the API defines its meaning.

Absent and present with a value of zero are not always equivalent either. If the difference changes the behavior, it can be represented by `(T, bool)`, a pointer, or a named result. The transport formats are translated in the adapter so that the module receives meaning, not serialization details.

## Autonomous dependencies

A dependency is part of the construction when the module cannot fulfill its contract without it. Receiving it through an API makes what it needs visible, but does not transfer its coordination to the consumer.

It is not necessary to introduce an interface for each helper. A dependency deserves its own contract when it has other consumers or suppliers, crosses a relevant boundary or evolves autonomously. At that point the same fundamentals can be applied again.

## Hands-on review

1. The API expresses a complete intent to its consumer.
2. The module governs its dependencies and preserves its invariants.
3. The creation produces a valid module or an explicit failure.
4. Each result contains the meaning necessary to act.
5. No results share mutable state with the provider.
6. Slices, maps, pointers and internal elements have clear ownership.
7. The same review is repeated at each relevant granular boundary.

> **Autonomy is preserved from the module to the result that crosses its API.**
