← Todos los temas
Día 17 · Trabajar en equipo

PRDs, RFCs y design docs: los planos del software

Qué documentos escriben los buenos equipos antes de programar y por qué ahorran dinero.

Definición

Un PRD, un design doc y un RFC son documentos que un equipo escribe antes de programar para decidir por escrito qué se va a construir, por qué y cómo. El PRD (Product Requirements Document, documento de requisitos del producto) define el problema, los usuarios y el resultado esperado; el design doc (documento de diseño) explica cómo se va a construir técnicamente y qué alternativas se descartaron; el RFC (Request for Comments, solicitud de comentarios) es una propuesta abierta a la crítica de todos los afectados antes de tomar una decisión discutible.

Cumplen la misma función que los planos en una obra: las decisiones caras se toman en papel, donde corregir cuesta una goma, y no en código ya construido, donde corregir cuesta tirar paredes. Un cuarto formato, el ADR (Architecture Decision Record, registro de decisiones de arquitectura), guarda de forma breve cada decisión ya tomada para que el equipo sepa después por qué el sistema es como es.

El ejemplo más citado es Amazon: antes de construir un producto escribe un PR/FAQ, un comunicado de prensa ficticio como si el producto ya existiera, más sus preguntas frecuentes. Según la propia empresa, el comunicado es «unos pocos párrafos, siempre menos de una página» y las preguntas frecuentes, «cinco páginas o menos».

Los cuatro documentos

DocumentoPregunta que respondeQuién lo escribeExtensión típica
PRD¿Qué problema resolvemos, para quién y cómo sabremos que funcionó?Producto (product manager), con diseño e ingenieríaBreve: lo justo para acordar problema, alcance y métricas
Design doc¿Cómo lo construimos y por qué de esta forma y no de otra?Ingeniería: quien liderará la implementación1–3 páginas para un cambio acotado; 10–20 para un sistema grande
RFC¿Estamos de acuerdo con esta propuesta antes de decidir?Cualquier persona que proponga un cambio que afecta a otrosVariable; suele seguir una plantilla fija
ADR¿Qué decidimos, en qué contexto y con qué consecuencias?Quien tomó o documentó la decisión1–2 páginas

El orden habitual es PRD → design doc → (RFC si la decisión es discutible) → ADR con la decisión final. En equipos pequeños, el PRD y el design doc pueden ser un solo documento con dos partes.

Estructura de un PRD

SecciónContenido
ProblemaQué le pasa hoy al usuario o al negocio, con evidencia (datos, quejas, entrevistas)
UsuariosA quién va dirigido y a quién no
Objetivos y métricasQué debe cambiar y cómo se mide, con un número y un plazo
RequisitosLo que el producto debe hacer, priorizado (indispensable, deseable)
Fuera de alcanceLo que deliberadamente no se hará en esta versión
Preguntas abiertasLo que falta decidir y quién lo decide

Un PRD describe el qué y el porqué, no el cómo: si empieza a elegir bases de datos o frameworks, ese contenido pertenece al design doc.

Estructura de un design doc

Malte Ubl, ingeniero de Google, describe en su blog personal las secciones que suelen tener los design docs de esa empresa. Con dos añadidos prácticos (riesgos y plan de pruebas), queda así:

SecciónContenido
Contexto y alcanceEl panorama actual y qué se construye, con hechos, no con requisitos
Objetivos y no objetivosLo que se busca y lo que podría ser un objetivo pero se deja fuera a propósito
Diseño propuestoVisión general y después detalle: APIs, datos, diagramas de contexto. Rara vez código
Alternativas consideradasOtros diseños viables y por qué el elegido cumple mejor los objetivos
Temas transversalesSeguridad, privacidad, observabilidad (día 14), costo
RiesgosQué puede salir mal y cómo se mitiga
Plan de pruebas y despliegueCómo se valida y cómo se libera (día 7), incluido cómo revertir
Métricas de éxitoNúmeros concretos que dirán si funcionó

Ubl propone un mini design doc de 1 a 3 páginas para mejoras incrementales y advierte que, si un documento parece un manual de implementación sin alternativas ni trade-offs, conviene escribir el código directamente.

RFC y ADR

Un RFC convierte el design doc en una conversación abierta. Los proyectos de código abierto lo usan como proceso formal:

  • Rust exige un RFC para cualquier cambio sustancial al lenguaje, a Cargo o a crates.io: se copia la plantilla 0000-template.md, se abre un pull request y, antes de decidir, hay un periodo final de comentarios de diez días naturales.
  • Python usa las PEP (Python Enhancement Proposals): documentos de diseño con secciones fijas, entre ellas motivación, especificación, justificación, compatibilidad hacia atrás, implicaciones de seguridad e ideas rechazadas.

Un ADR es mucho más corto. Michael Nygard lo propuso en 2011 con cinco partes: título, contexto (las fuerzas en juego), decisión, estado (propuesta, aceptada, reemplazada) y consecuencias. Se guarda en el repositorio junto al código, numerado (docs/adr/0007-usar-postgresql.md), y no se edita: si la decisión cambia, se escribe un ADR nuevo que reemplaza al anterior.

Alternativas y trade-offs

Un trade-off es lo que ganas y lo que sacrificas con cada opción. La sección de alternativas es la más útil para los revisores, porque muestra que el diseño elegido se comparó con otros:

  • Presenta al menos dos alternativas reales, no una opción absurda para que la elegida luzca mejor. «No hacer nada» suele ser una alternativa válida.
  • Para cada una, escribe en una frase qué gana y qué pierde, medido contra los objetivos declarados y no contra preferencias personales.
  • Indica qué información haría cambiar la decisión (por ejemplo, «si el volumen supera X, conviene la alternativa B»).

Puertas de una vía y de dos vías

Jeff Bezos, en la carta a los accionistas de Amazon de 2015, separa dos tipos de decisiones. Las de tipo 1 son consecuentes e irreversibles o casi irreversibles: puertas de una sola vía, que deben tomarse con método, cuidado y consulta. Las de tipo 2 son cambiables y reversibles: puertas de dos vías, que conviene tomar rápido y en grupos pequeños, porque si salen mal se puede volver atrás.

DecisiónTipoDocumento recomendado
Esquema de la base de datos con datos de clientes, API pública, proveedor de pagosUna vía (difícil de revertir)Design doc completo y RFC; ADR al decidir
Nueva pantalla o función detrás de un feature flagDos vías (se apaga)Mini design doc o descripción en el pull request
Renombrar una función interna, ajustar un estiloDos vías y localNinguno: basta la revisión de código (día 18)

El error frecuente es tratar todas las decisiones como de una vía: el equipo se vuelve lento sin ganar seguridad.

Cuándo escribirlos y cuándo no

SituaciónRecomendación
Cambio pequeño, local y reversibleSin documento; explícalo en el pull request
Función nueva de una o dos semanas de trabajoMini design doc (1–3 páginas)
Proyecto de varias semanas o varios equiposPRD + design doc con revisión formal
Decisión irreversible o que afecta a muchos (API pública, migración de datos, seguridad)Design doc + RFC con periodo de comentarios + ADR
El problema no es ambiguo y solo hay una solución razonableNo escribas un design doc: el costo supera el beneficio

Proceso de revisión

  1. Borrador con uno o dos colaboradores cercanos, iterando rápido.
  2. Revisión: se comparte con los equipos afectados y con revisores elegidos por área (seguridad, datos, pagos), no por jerarquía. Los comentarios van en el propio documento, con fecha límite.
  3. Decisión explícita, con nombre de quien decide y fecha. Si hubo desacuerdo, queda registrado.
  4. Implementación y aprendizaje: si el plan cambia, se actualiza el documento; meses después se relee para ver qué se acertó.

Errores comunes

  • Escribir después de programar, para justificar lo ya hecho: el documento pierde su valor principal.
  • Alternativas de paja (opciones que nadie elegiría) y métricas sin número («mejorar la experiencia»).
  • No objetivos ausentes: el alcance crece sin control.
  • Documento abandonado o revisión eterna: sin responsable ni fecha límite, describe un sistema que no existe o la decisión nunca llega.

Práctica: revisar un design doc con un script

Este ejemplo es un mini design doc ficticio para agregar pagos con anticipo a una API de reservas (las cifras son metas de ejemplo). Guárdalo como design-doc.md:

# Design doc: pagos con anticipo en la API de reservas

## Contexto
Hoy `POST /reservas` confirma la reserva sin cobrar nada. El negocio pide un anticipo para reducir las ausencias.

## Objetivos y no objetivos
- Objetivo: cobrar un anticipo del 20 % al reservar y confirmar la reserva solo si el pago se aprueba.
- No objetivo: reembolsos automáticos (siguen siendo manuales en esta versión).

## Diseño propuesto
`POST /reservas` crea la reserva en estado `pendiente_pago` y una intención de pago en el proveedor, con una llave de idempotencia igual al id de la reserva. El webhook `pago.aprobado` la pasa a `confirmada`; si no llega en 15 minutos, una tarea la pasa a `vencida` y libera el horario.

## Alternativas consideradas
### Cobrar el total al reservar
Trade-off: es lo más simple de construir, pero un cobro alto al reservar puede bajar las reservas.
### Retener la tarjeta sin cobrar
Trade-off: no cobra nada si el cliente llega, pero la retención vence antes que las reservas hechas con semanas de anticipación.

## Riesgos
El webhook puede llegar dos veces o fuera de orden: se procesa por id de evento y se ignoran los repetidos.

## Plan de pruebas
Pruebas de integración con el modo de prueba del proveedor: pago aprobado, rechazado, webhook duplicado y reserva vencida.

## Métricas de éxito
- Ausencias en fin de semana: por debajo de 8 % a los 60 días.
- Reservas completadas: caída menor a 5 % frente al mes anterior.

1. Guarda el revisor como revisa_design_doc.py (solo biblioteca estándar):

"""Revisa un design doc antes de pedir revisión: secciones obligatorias con contenido,
al menos 2 alternativas con su trade-off y métricas con número. Uso: python revisa_design_doc.py doc.md
"""
import re
import sys

OBLIGATORIAS = ["Contexto", "Objetivos y no objetivos", "Diseño propuesto", "Alternativas consideradas",
                "Riesgos", "Plan de pruebas", "Métricas de éxito"]
VACIO = re.compile(r"^(tbd|todo|pendiente|por definir|n/a)?\W*$", re.IGNORECASE)


def secciones(md: str, nivel: str = "##") -> dict[str, str]:
    # {título: contenido} de cada encabezado del nivel indicado.
    partes = re.split(rf"^{nivel} +(.+?)\s*$", md, flags=re.MULTILINE)
    return {t: c.strip() for t, c in zip(partes[1::2], partes[2::2])}


def revisar(md: str) -> list[str]:
    errores, s = [], secciones(md)
    for nombre in OBLIGATORIAS:
        if nombre not in s:
            errores.append(f"falta la sección «{nombre}»")
        elif VACIO.match(s[nombre]):
            errores.append(f"la sección «{nombre}» está vacía")
    alternativas = secciones(s.get("Alternativas consideradas", ""), "###")
    con_tradeoff = [a for a, c in alternativas.items() if re.search(r"trade-off:\s*\S", c, re.IGNORECASE)]
    for a in [a for a in alternativas if a not in con_tradeoff]:
        errores.append(f"la alternativa «{a}» no explica su trade-off")
    if len(con_tradeoff) < 2:
        errores.append(f"hay {len(con_tradeoff)} alternativa(s) con trade-off; se piden al menos 2")
    for linea in re.findall(r"^- +(.+)$", s.get("Métricas de éxito", ""), flags=re.MULTILINE):
        if not re.search(r"\d", linea):
            errores.append(f"métrica sin número: «{linea}»")
    return errores


if __name__ == "__main__":
    ruta = sys.argv[1]
    errores = revisar(open(ruta, encoding="utf-8").read())
    print(f"Revisando {ruta}")
    for e in errores:
        print(f"  ERROR  {e}")
    if errores:
        print(f"Resultado: {len(errores)} problema(s). Corrígelos antes de pedir revisión.")
        sys.exit(1)
    print("Resultado: listo para revisión (7 secciones, 2+ alternativas con trade-off, métricas con número).")

2. Pruébalo con una versión mala. Guarda como design-doc-malo.md un borrador típico: sin objetivos ni riesgos, con «TBD» en el plan de pruebas, una sola alternativa sin trade-off («Es más simple.») y la métrica «Que haya menos ausencias.». Ejecuta python revisa_design_doc.py design-doc-malo.md. Salida real (Python 3.12, Windows), con código de salida 1:

Revisando design-doc-malo.md
  ERROR  falta la sección «Objetivos y no objetivos»
  ERROR  falta la sección «Riesgos»
  ERROR  la sección «Plan de pruebas» está vacía
  ERROR  la alternativa «Cobrar el total al reservar» no explica su trade-off
  ERROR  hay 0 alternativa(s) con trade-off; se piden al menos 2
  ERROR  métrica sin número: «Que haya menos ausencias.»
Resultado: 6 problema(s). Corrígelos antes de pedir revisión.

3. Ejecútalo con la versión buena: python revisa_design_doc.py design-doc.md. Salida real, con código de salida 0:

Revisando design-doc.md
Resultado: listo para revisión (7 secciones, 2+ alternativas con trade-off, métricas con número).

4. Úsalo en tu flujo. Como devuelve 1 cuando falla, puedes ejecutarlo en CI (día 7) sobre la carpeta docs/design/ para que ningún documento llegue a revisión incompleto. El script comprueba la forma, no el fondo: decidir si el diseño es bueno sigue siendo trabajo de los revisores.

Skill gratis para Claude: planos-de-software lee tu proyecto y te escribe el PRD y el design doc de tu siguiente cambio con alternativas, riesgos y plan de pruebas, y comprueba con un script que no falte ninguna sección y que cada archivo citado exista.

Preguntas frecuentes

¿Cuál es la diferencia entre un PRD y un design doc?

El PRD dice qué se construye, para quién y por qué; lo escribe producto. El design doc dice cómo se construye y qué alternativas se descartaron; lo escribe ingeniería.

¿Qué es un RFC en software?

Es una propuesta escrita que se abre a comentarios de todos los afectados antes de decidir. Rust y Python (con las PEP) lo usan para cambios importantes en el lenguaje.

¿Siempre hay que escribir un design doc?

No. Para cambios pequeños, reversibles o sin ambigüedad basta con explicar el cambio en el pull request. Se justifica cuando la decisión es cara de revertir o afecta a varias personas.

¿Qué es el PR/FAQ de Amazon?

Es un comunicado de prensa escrito como si el producto ya existiera, de menos de una página, con preguntas frecuentes de cinco páginas o menos. Se escribe antes de construir para comprobar que la idea vale la pena.

En el reel lo explicamos así

Antes de construir una casa se hacen planos; antes de programar, también. Corregir un plano cuesta una goma; tirar una pared ya construida cuesta mucho más. El PRD dice qué se construye y para quién; el design doc, cómo se hará y qué alternativas se descartaron; y si la decisión es discutible, se abre como RFC para que todos comenten antes de decidir. Amazon, antes de construir un producto, escribe el comunicado de prensa como si ya existiera, en menos de una página, y sus preguntas frecuentes.

Referencias

En el reel lo explicamos así

Los planos de una casa: corregir un plano cuesta una goma; tirar una pared ya construida cuesta mucho más.

Glosario: del inglés al español

PRD · Product Requirements Documentdocumento de requisitos del producto
RFC · Request for Commentspropuesta abierta a comentarios
Design docdocumento de diseño
Trade-offlo que ganas y lo que sacrificas