Toma de Decisiones Técnicas
Los líderes técnicos eligen entre opciones imperfectas en condiciones de incertidumbre. Las decisiones clasificadas hacen explícitas las compensaciones, documentan las elecciones incorrectas y establecen desencadenantes de revisión para que las elecciones de la pila de Python (FastAPI vs Django, síncrono vs asíncrono) no se conviertan en religión permanente.
Cómo Usar Esta Lista
- Evalúa las decisiones en orden al planificar la arquitectura o las actualizaciones.
- Registra el rango elegido y por qué en un ADR o ticket.
- Establece un desencadenante de revisión (escala, tamaño del equipo, incumplimiento de SLO) para las llamadas reversibles.
- Usa spikes para reducir el riesgo de las opciones "secundarias" antes de comprometerte con la "Mejor".
- Revisa cuando se active el desencadenante; reemplaza el ADR, no te desvíes silenciosamente.
Decisión 1: Framework HTTP para una nueva API de Python
Escenario: API B2B Greenfield, 6 ingenieros, SLO p95 200ms, Postgres, necesita OpenAPI.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | FastAPI | Rutas asíncronas, Pydantic v2, OpenAPI nativo, cliente de prueba httpx |
| 2º | Django + DRF | Administración, madurez del ORM, grupo de contratación; más pesado por solicitud |
| 3º | Flask | Mínimo; componer extensiones; menos funcionalidades incluidas |
Elección incorrecta: Flask para más de 40 endpoints sin disciplina: proliferación de blueprints y validación inconsistente.
Por qué la mejor es la mejor: El SLO del equipo y los contratos tipados favorecen a FastAPI; ya existe un plugin de autenticación interna compartido.
Decisión 2: Workers síncronos Gunicorn vs asíncronos Uvicorn
Escenario: API CRUD, principalmente I/O de Postgres, ocasional CPU en generación de PDF.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | Gunicorn síncrono + pool de hilos para CPU | Modelo mental simple; SQLAlchemy síncrono bien transitado |
| 2º | Uvicorn asíncrono | Si WebSockets o I/O concurrente de alto fan-out |
| 3º | Síncrono + gevent | Legado; depuración más difícil |
Elección incorrecta: Asíncrono en todas partes con ORM síncrono en rutas: interrupciones por bloqueo del bucle de eventos.
Por qué la mejor es la mejor: La carga de trabajo está limitada por I/O, pero el equipo conoce SQLAlchemy síncrono; las partes de CPU están aisladas en ProcessPoolExecutor.
Decisión 3: Monolito vs servicios divididos
Escenario: 8 ingenieros, un producto, Postgres compartido, despliegue semanal.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | Monolito modular | Límites claros de paquetes; despliegue único; extraer más tarde |
| 2º | Dos servicios (API + workers) | Cuando la escala de Celery y el dominio de fallo difieren |
| 3º | Microservicios por dominio | Impuesto operativo prematuro |
Elección incorrecta: Cinco microservicios antes de que exista un segundo equipo: CFR y tiempo de entrega sufren.
Por qué la mejor es la mejor: El tamaño del equipo y los límites de las transacciones encajan en un solo despliegable con módulos.
Decisión 4: SQLAlchemy síncrono vs motor asíncrono
Escenario: Servicio FastAPI considerando SQLAlchemy 2.0 asíncrono.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | Motor síncrono + pool de hilos | Si el equipo es nuevo en DB asíncrona; menos sorpresas con el pool |
| 2º | Motor asíncrono (asyncpg) | I/O de lectura de alta concurrencia, equipo capacitado |
| 3º | Solo SQL crudo | Raro; pierde productividad del ORM |
Elección incorrecta: Motor asíncrono con llamadas bloqueantes en dependencias: agotamiento del pool enmascarado como latencia.
Por qué la mejor es la mejor: La madurez del escuadrón y la concurrencia moderada aún no justifican la complejidad de la base de datos asíncrona.
Decisión 5: Tareas en segundo plano en proceso vs Celery
Escenario: Enviar correo electrónico, generar PDF, facturación nocturna: tareas de minutos de duración.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | Celery + broker Redis | Reintentos, visibilidad, escala workers de forma independiente |
| 2º | BackgroundTasks de FastAPI | Solo para <2s de "disparar y olvidar" |
| 3º | Dramatiq / RQ | Menor huella operativa; menos características |
Elección incorrecta: BackgroundTasks para lotes de facturación: mata los workers de la API bajo carga.
Por qué la mejor es la mejor: La duración de la tarea y la política de reintentos necesitan una cola real con DLQ.
Decisión 6: Configuración Pydantic vs analizador de entorno personalizado
Escenario: Configuración de doce factores en entornos de desarrollo/staging/producción.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | pydantic-settings | Arranque tipado y validado; .env solo para local |
| 2º | python-decouple | Ligero; menos validación |
| 3º | os.environ manual | Propenso a errores a escala |
Elección incorrecta: os.getenv disperso sin validación: producción arranca con DATABASE_URL vacío.
Por qué la mejor es la mejor: La validación de fallo rápido coincide con los estándares de la flota; se empareja con modelos Pydantic en otros lugares.
Decisión 7: Estrictez de verificación de tipos en CI
Escenario: Monolito de 200k LOC mixto tipado/no tipado.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | Pyright gradual en rutas modificadas | reportMissingImports estricto en CI para paquetes tocados |
| 2º | mypy estricto módulo por módulo | Más lento; bueno para bibliotecas |
| 3º | Sin tipos en CI | La deuda se acumula |
Elección incorrecta: Cambiar todo el repositorio a estricto de la noche a la mañana: meses de cambios bloquean la entrega.
Por qué la mejor es la mejor: La puerta de enlace de rutas modificadas mejora la calidad sin detener el trabajo de funciones.
Decisión 8: Empaquetado con uv vs Poetry
Escenario: Repositorio de nuevo servicio, equipo estandarizando la cadena de herramientas.
| Rango | Elección | Enfoque |
|---|---|---|
| Mejor | uv + pyproject.toml + lock | CI rápida, compatible con pip, opción moderna por defecto |
| 2º | Poetry | Maduro; CI más lenta; equipo ya experto |
| 3º | Solo pip-tools | Funciona; UX de desarrollo menos ergonómica |
Elección incorrecta: Sin archivo de bloqueo en imágenes de producción: incidentes de deriva de dependencias.
Por qué la mejor es la mejor: La organización se está moviendo a uv 0.6+; hash de bloqueo en las etiquetas de la imagen.
Preguntas Frecuentes
¿Cuántas opciones por decisión?
Tres opciones clasificadas más una elección incorrecta explícita es suficiente; más crea parálisis de análisis.
¿Cuándo ejecutar un spike?
Cuando dos opciones puntúan dentro del 10% ponderado: limitar el tiempo a 2-3 días con criterios de éxito.
¿Quién rompe los empates?
El líder técnico o arquitecto documenta la decisión; el EM solo considera el riesgo del cronograma.
¿Qué tan reversibles son estas decisiones?
Los marcos y las divisiones de monolitos son costosos: establezca desencadenantes de revisión. La configuración y las banderas son baratas.
¿Votan los clientes?
Entrada del producto sobre los resultados; la ingeniería posee los rangos técnicos.
¿Cómo documentar?
Enlace a Registros de Decisiones de Arquitectura (ADR) para registro persistente.
¿Qué pasa con construir vs comprar?
Misma tabla clasificada: construir, comprar, posponer con una llamada de atención sobre la elección incorrecta para una construcción prematura.
¿Cómo manejar incidentes urgentes?
El IC puede eludir el proceso; hacer seguimiento con un ADR de retrospectiva dentro de una semana.
¿Actualizaciones de versión de Python?
Rango: actualización menor in situ vs despliegue lado a lado vs retraso; vincular a la política de EOL.
¿Cuándo revisar una decisión?
Cuando se activa el desencadenante de revisión: tráfico 2x, equipo +50%, o clase de incidente repetida.
Relacionado
- Registros de Decisiones de Arquitectura (ADR) - persistir elecciones
- Ejecución de Revisiones de Diseño - socializar opciones
- Manejo de Desacuerdos Técnicos - discrepar y comprometerse
- Decisiones de Arquitectura de Python - catálogo de patrones
- Mejores Prácticas de Liderazgo - hábitos del equipo
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.