Todos los artículos

De desarrollador a arquitecto: el cambio de mentalidad del que nadie habla

La transición de escribir código a diseñar sistemas no consiste en aprender nuevas herramientas, sino en cambiar de raíz la forma en que piensas sobre el software.

8 min de lectura
  • #architecture
  • #career
  • #software-engineering
  • #system-design
  • #growth

Hay un momento en la carrera de todo desarrollador senior en el que te das cuenta de que escribir gran código ya no es suficiente. Los problemas que enfrentas no se resuelven con un algoritmo ingenioso ni con un patrón de diseño bien ubicado. Requieren que tomes distancia (mucha distancia) y pienses en los sistemas como un todo.

Esa transición de desarrollador a arquitecto me desordenó la cabeza durante un tiempo. No porque sea técnicamente más difícil, sino porque exige que desaprendas hábitos que te hicieron exitoso como desarrollador. Esto es lo que ese cambio significa en realidad.

Pensar en trade-offs, no en absolutos

Como desarrollador, solía pensar en términos de “la forma correcta” de hacer las cosas. Las bases de datos normalizadas son mejores. Los microservicios son el futuro. El tipado fuerte previene bugs. Todo eso me parecía verdad universal.

Como arquitecto, aprendí que casi nada es universalmente cierto. Todo es un trade-off, y tu trabajo es elegir el que menos duele en tu contexto específico.

¿Deberías usar microservicios? Depende del tamaño de tu equipo, de tu capacidad de deploy y de qué tan bien entiendas los límites de tu dominio. ¿Deberías normalizar tu base de datos? Depende de tu proporción de lecturas y escrituras y de si puedes permitirte la complejidad de los joins a escala.

El reflejo de “depende” del que se burlan los desarrolladores junior es, en realidad, sabiduría ganada a pulso. Significa que has visto suficientes sistemas triunfar y fracasar como para saber que el contexto lo determina todo.

Un ejemplo real. En un proyecto del año pasado, tuve que decidir entre:

  • Opción A: Arquitectura orientada a eventos con Kafka: técnicamente elegante, excelente para escalar, compleja de operar
  • Opción B: Llamadas REST simples entre servicios con una base de datos PostgreSQL compartida: “aburrida”, pero el equipo podía entregarla y mantenerla

Elegí la Opción B. El equipo eran cuatro desarrolladores, ninguno tenía experiencia con Kafka y teníamos un plazo de tres meses. La Opción A habría sido arquitectónicamente “mejor” en el vacío. En nuestro contexto, habría sido un desastre.

El trabajo del arquitecto no es elegir la mejor solución. Es elegir la mejor solución para este equipo, este calendario y este conjunto de restricciones.

El peligro de la arquitectura de torre de marfil

He trabajado con arquitectos que diseñan sistemas desde una pizarra y nunca miran el código. Producen diagramas hermosos, ADRs exhaustivos y arquitecturas que se desmoronan en cuanto los desarrolladores empiezan a implementarlas.

Los mejores arquitectos que conozco, aquellos cuyos sistemas realmente funcionan en producción, todavía leen código a diario. No porque desconfíen de sus equipos, sino porque el código es donde la arquitectura se encuentra con la realidad.

Cuando reviso pull requests, no busco problemas de estilo ni nombres de variables. Busco:

  • ¿Los límites que diseñé realmente se sostienen, o los desarrolladores los están rodeando?
  • ¿La abstracción que propuse realmente reduce la complejidad, o la aumenta?
  • ¿Están surgiendo en el código patrones que sugieren que la arquitectura necesita evolucionar?
// Este es un code smell que busco en las revisiones de código.
// Cuando ves que un servicio importa directamente los tipos
// internos de otro servicio, se ha violado el límite arquitectónico.

import (
    "github.com/company/user-service/internal/models"  // BANDERA ROJA
    "github.com/company/order-service/domain"
)

// Cómo debería verse:
import (
    "github.com/company/shared/contracts"  // Interfaz compartida
    "github.com/company/order-service/domain"
)

Si tu arquitectura no puede sobrevivir al contacto con desarrolladores reales escribiendo código real bajo plazos reales, no es arquitectura: es ficción.

La comunicación es la herramienta principal del arquitecto

Esto me tomó por sorpresa. Pensaba que convertirme en arquitecto significaba dedicar más tiempo a problemas técnicos. En realidad, paso más tiempo comunicando que programando.

Una decisión de arquitectura que el equipo no entiende no vale nada. Necesitas:

  • Explicar el “por qué” detrás de cada decisión importante. No solo qué estamos haciendo, sino por qué este enfoque y no las alternativas
  • Crear modelos mentales compartidos. Cuando digo “bounded context”, todos los desarrolladores del equipo deberían imaginar lo mismo
  • Escuchar las objeciones. Los desarrolladores en el terreno ven cosas que tú no puedes ver desde el nivel de la arquitectura. Si tres desarrolladores te dicen que la abstracción es dolorosa, créeles
  • Dejarlo por escrito. Los Architecture Decision Records (ADRs) no son burocracia: son la memoria de tu equipo

Una vez diseñé lo que pensaba que era un elegante sistema de event sourcing. Durante la revisión del diseño, un desarrollador de nivel intermedio preguntó: “¿Cómo depuramos esto cuando algo falle a las 3 AM?”. No tenía una buena respuesta. Esa pregunta nos ahorró meses de dolor. El desarrollador no necesitaba entender la teoría de event sourcing; necesitaba entender la realidad operativa. Y tenía razón.

Cómo DDD cambió mi forma de pensar

Domain-Driven Design fue la mayor influencia en mi transición hacia el pensamiento arquitectónico. No por los patrones tácticos (aggregates, repositories, value objects), sino por los estratégicos.

DDD me enseñó a:

  1. Empezar por el dominio, no por la tecnología. Antes de pensar en bases de datos o frameworks, dedico tiempo a entender el problema de negocio. ¿Cuáles son las entidades? ¿Cuáles son los procesos? ¿Dónde están los límites?

  2. Hablar el lenguaje del dominio. Si el negocio lo llama “póliza” y tu código lo llama “contrato”, has creado una capa de traducción que causará bugs y malentendidos para siempre.

  3. Identificar bounded contexts. Este es el concepto más poderoso de DDD. No todo necesita compartir el mismo modelo. El “Usuario” en el contexto de facturación es distinto del “Usuario” en el contexto social, y eso no solo está bien: es lo correcto.

# Antes de pensar con DDD:
Un modelo User gigante con 47 campos que sirve a 6 contextos distintos

# Después de pensar con DDD:
- Billing::Customer (email, payment_method, subscription_tier)
- Social::Profile (display_name, avatar, bio)
- Auth::Identity (credentials, mfa_settings, sessions)
- Support::Requester (name, contact_info, ticket_history)

Cada contexto es dueño de su modelo. Se comunican mediante interfaces bien definidas. Los cambios en uno no se propagan a los demás. Esto no es sobreingeniería: es reconocer que un único modelo que sirve a todos en realidad no sirve bien a nadie.

Tomar decisiones con información incompleta

Como desarrollador, podía reunir todos los requisitos, entender el alcance completo y luego construir. Como arquitecto, casi nunca tengo información completa cuando debo tomar decisiones.

Eliges un sistema de mensajería antes de conocer los requisitos finales de escala. Diseñas los límites de los servicios antes de que el modelo de negocio esté plenamente validado. Eliges un proveedor de nube antes de saber qué regiones vas a necesitar.

Esto solía paralizarme. ¿Y si me equivoco? A esta escala, equivocarse sale caro.

Esto es lo que he aprendido: el costo de no decidir casi siempre es mayor que el costo de una decisión equivocada. Una decisión equivocada se puede corregir. La indecisión bloquea a equipos enteros.

Mi marco para decidir bajo incertidumbre:

  • Haz la decisión reversible si es posible. Usa abstracciones que te permitan cambiar las implementaciones más adelante. Aquí es donde la arquitectura de puertos y adaptadores brilla
  • Fija una fecha de revisión. “Por ahora vamos con PostgreSQL. En tres meses evaluaremos si necesitamos migrar a una base de datos distribuida según datos reales de carga”
  • Documenta tus supuestos. Cuando escribes “Asumimos menos de 10 000 usuarios concurrentes en el Año 1”, creas una alarma que le avisa a tu yo del futuro cuándo hay que revisar la decisión
  • Acepta que algunas decisiones serán erróneas. Diseña tu sistema para que las decisiones equivocadas no lo tumben todo. El bajo acoplamiento no es solo una palabra de moda: es un seguro

El miedo a equivocarse a escala

Cuando eres desarrollador y escribes un bug, afecta a una funcionalidad. Quizás unos pocos usuarios ven un mensaje de error. Lo corriges, haces deploy y sigues adelante.

Cuando eres arquitecto y tomas una mala decisión estructural, puede afectar a todos los equipos, todos los servicios y todos los deploys durante meses o años. Ese peso es real, y fingir que no existe no ayuda.

Lo manejo así:

  • Construyendo pruebas de concepto antes de comprometerme con decisiones arquitectónicas importantes. Un spike de dos semanas es barato comparado con una reescritura de seis meses
  • Pidiendo opinión a otros ingenieros con experiencia. Las revisiones de arquitectura no son señal de debilidad, sino de madurez
  • Estudiando los fracasos. Aprendo más de los post-mortems que de las historias de éxito. Cuando un sistema falla, las debilidades de la arquitectura se hacen visibles

De “yo lo construyo” a “lo diseño para que otros puedan construirlo”

La parte más difícil de esta transición fue soltar el código. Como desarrollador, mi identidad estaba ligada a lo que construía. Como arquitecto, mi valor viene de permitir que otros construyan bien.

Esto significa:

  • Escribir especificaciones claras en lugar de escribir tú mismo el código
  • Confiar en que tu equipo tomará las decisiones de implementación dentro de los límites que has fijado
  • Medir el éxito por el resultado del equipo, no por el personal
  • Estar tranquilo con soluciones que no son como tú las habrías programado, siempre que respeten la arquitectura

Es un tipo distinto de satisfacción. En lugar de mirar una funcionalidad y pensar “yo construí eso”, miras un sistema y piensas “yo diseñé la estructura que permitió que doce personas construyeran eso sin pisarse unas a otras”.

Una reflexión final

La transición de desarrollador a arquitecto no es un ascenso: es un cambio de carrera. Las habilidades que te hicieron un gran desarrollador (concentración profunda, atención al detalle, resolución práctica de problemas) no desaparecen, pero pasan a ser habilidades de apoyo en lugar de principales.

Tus habilidades principales pasan a ser: pensamiento sistémico, comunicación, toma de decisiones bajo incertidumbre y la humildad de saber que tu hermosa arquitectura será doblada, rota y parchada por la realidad.

¿Y sinceramente? Eso es lo que lo hace fascinante. Ya no estás construyendo software. Estás diseñando el entorno donde se construye el software. Haz bien eso, y todo lo demás viene solo.