Aleatoriza lo que no garantizas
Los errores de tu API son las funciones de alguien. Así que rómpelos a propósito.
Toda API tiene dos superficies: el contrato que documentaste y el conjunto mucho mayor de comportamientos que simplemente resultan ser ciertos hoy. El orden de los resultados, los tiempos, la redacción exacta de un mensaje, si una lista tiene duplicados. Nunca prometiste nada de eso, pero en cuanto un consumidor nota que funciona de cierta forma, alguien escribe código que se apoya en ello. Y luego no puedes cambiarlo sin romperlo.
La ley de Hyrum
La observación de Hyrum Wright es contundente: con una cantidad suficiente de usuarios de una API, no importa lo que prometas en el contrato — todos los comportamientos observables de tu sistema serán dependidos por alguien. La documentación es irrelevante para la falla. Si un comportamiento es alcanzable, a escala es estructural.
El ejemplo clásico es el orden de iteración. Un mapa hash o un SELECT sin ORDER BY devuelve filas en algún orden. No es parte del contrato, pero es lo bastante estable día a día como para que los consumidores lo asuman en silencio. Cambia tu motor de almacenamiento, actualiza una librería, y el orden cambia. Su código se rompe, y el reporte del bug cae sobre ti.
Aleatoriza lo no garantizado
La solución es contraintuitiva: haz que el comportamiento no garantizado sea visiblemente poco confiable, en desarrollo y pruebas, para que nadie pueda acoplarse a él.
import os, random
def list_items(rows):
# El orden NO es parte del contrato de esta API.
# Mézclalo fuera de producción para que nadie dependa del orden incidental.
if os.environ.get("ENV") != "production":
rows = list(rows)
random.shuffle(rows)
return rows
Si la respuesta no tiene orden garantizado, mézclala. Si un campo es opcional, a veces omítelo. Si un conjunto no tiene secuencia definida, varíala. La dependencia incidental del consumidor ahora falla rápido en su propia suite de pruebas, en lugar de osificarse en silencio en un contrato que nunca firmaste.
La iteración de mapas en Go es la implementación canónica de esta idea: el runtime aleatoriza deliberadamente el orden de iteración para que ningún programa pueda depender de él. La aleatorización es la funcionalidad.
Qué aleatorizar vs garantizar
| Comportamiento | ¿Garantizado en el contrato? | Acción |
|---|---|---|
| Orden de sort documentado | Sí | Mantenlo estable; pruébalo |
| Orden incidental de filas | No | Mézclalo en dev/test |
| Formato del cursor de paginación | No (opaco) | Rota/ofusca el token |
| Presencia de campos opcionales | No | Ocasionalmente omítelos |
| Precisión de timestamp | No | Varía dentro del límite prometido |
La regla: todo lo que esté dentro del contrato, asegúralo y pruébalo a fondo. Todo lo que quede fuera, agítalo para que no se vuelva un contrato en silencio.
Movidas avanzadas
- Haz explícita la promesa. Si el orden debería estar garantizado, documéntalo y agrega
ORDER BY; así los consumidores pueden confiar en él legítimamente. - Tokens opacos. Devuelve cursores de paginación e IDs como blobs opacos. Si nadie puede parsear el formato, nadie depende de sus internos.
- Caos en staging. Extiende la idea más allá del orden: inyecta pequeña latencia y reintentos ocasionales fuera de producción para que los consumidores construyan resiliencia en vez de depender de la velocidad de hoy.
- Versiona antes de romper. Cuando debas cambiar una garantía real, publica una versión nueva en lugar de mutar la vieja.
Recursos
- La ley de Hyrum
- Go maps in action — el orden de iteración es aleatorio
- Capítulos de "API Deprecation" y "Backwards Compatibility" — Software Engineering at Google
- Versionado semántico
¿Desarrollas sistemas de IA o en la nube? Yeda AI audita y refuerza pipelines de LLM y APIs en producción. Hablemos · Lee el blog