Parte VII: Parte 7 — Patrones, principios y casos de estudio: las recetas que sobreviven al tiempo

Los patrones que la comunidad ha validado, los casos de estudio reales de empresas que lo hicieron, las métricas que importan y los anti-patrones que matan los proyectos. Esta es la parte donde paramos de hablar de "cómo se construye Backstage" y empezamos a hablar de "cómo se construye una Internal Developer Platform que sobreviva 5 años".

Patrones de implementación: las recetas que sobreviven al tiempo

Tiempo de lectura: 23 min · Itinerarios: cocinero jefe, CTO, consultor. Lee :cap-23 después para profundizar.

NOTE

.Objetivos del capítulo

Al terminar este capítulo vas a poder:

* Conocer los 8 patrones que la comunidad ha validado para implementar IDPs.
* Diferenciar entre MVP, plataforma completa y wrapper de UI.
* Aplicar "Platform as a Product" como mindset antes que como tecnología.
* Diseñar golden paths que se midan, no que se acumulen.
* Evitar el patrón "Field of Dreams" (construir y esperar que vengan).
====

// evidence: cl-spotify-200-plugins (Spotify webinar Oct 2025), cl-team-topologies (4 tipos de equipo)

=== Por qué importan los patrones

Construir una IDP no es un proyecto: es un **producto vivo** que sirve a developers. Y como cualquier producto, hay formas que sobreviven al tiempo y formas que mueren en 18 meses.

humor::
Un patrón es como una receta de cocina con cinco estrellas. La han probado cien cocineros, la han ajustado, y todos sobreviven al hacerla. Un anti-patrón es la receta que tu cuñado encontró en YouTube y que ha salido mal en cada familia que la prueba.

La diferencia entre un proyecto IDP que dura 5 años y uno que se abandona al año no es la tecnología. Es **cómo se pensó, cómo se vendió, cómo se mantuvo**. Los patrones que verás aquí vienen de:

* Spotify, Dynatrace, JPMorgan, American Airlines, LinkedIn, Twilio, Unity, Splunk, IKEA, HP — los casos públicos de empresas con Backstage en producción.
* Los principios del libro https://teamtopologies.com/[Team Topologies] de Skelton y Pais.
* Las 8 anti-patterns documentadas por https://www.infoworld.com/article/4064273/8-platform-engineering-anti-patterns.html[InfoWorld] y https://jellyfish.co/library/platform-engineering/anti-patterns[Jellyfish].
* La experiencia de campo del equipo de Backstage de Spotify en 200+ plugins internos.

=== Patrón 1: Platform as a Product (PaaP)

El patrón más importante. No es una tecnología, es una **postura mental**: la plataforma es un producto, los developers son clientes, y el equipo de plataforma es un equipo de producto.

humor::
"Platform as a Product" es lo que pasa cuando el equipo de plataforma deja de medir su éxito en "tickets cerrados" y empieza a medirlo en "developers auto-servidos". Es el cambio de "somos un help desk" a "somos un negocio que vende un servicio interno".

==== Lo que implica

[cols="1,3", options="header"]
|===
| Práctica | Qué significa

| Roadmap público
| El equipo de plataforma publica su roadmap trimestral. Los stream-aligned teams votan features.

| User research
| Antes de construir una feature, el equipo hace 5-10 entrevistas con developers. No asumen qué necesitan.

| Onboarding
| Cada nuevo developer tiene un "first day experience" con la plataforma. Onboarding medido en horas, no en semanas.

| Métricas de uso
| DAU/MAU, tiempo de onboarding, % de equipos usando la plataforma. No tickets cerrados.

| Marketing interno
| Demos en all-hands, newsletters, "what's new". Como cualquier producto.

| Versioning
| La plataforma tiene versión. Los breaking changes se anuncian. Hay LTS.
|===

==== Lo que NO es

* No es tener un `app-config.yaml` bonito.
* No es instalar Backstage y decir "ya está".
* No es tener un equipo grande de SREs contestando tickets.

NOTE::
**Test definitivo**: si un developer necesita ayuda humana para usar la plataforma, **la plataforma ha fallado**. El self-service no es un nice-to-have; es la definición misma de plataforma. Si la quitas y todo se rompe, tienes un help desk glorificado, no una plataforma.

=== Patrón 2: Minimum Viable Platform (MVP)

NOTE::
El error #1 de platform engineering es construir un sistema "completo" antes de tener usuarios. Es exactamente lo que el patrón **Field of Dreams** describe: "if you build it, they will come". Casi nunca vienen.

==== Cómo construir un MVP que sobreviva

[source,typescript]
----
// Antes: "voy a construir la plataforma completa"
// pipeline = "construir todo"
// coste = 6-12 meses sin feedback

// Después: "voy a resolver UN problema"
// pipeline = "resolver el dolor #1 de 5 equipos"
// coste = 6-8 semanas
----

**Pasos del MVP**:

. **Lista 20 fricciones de developers** (no plataformas, fricciones: "tarda 3 días en provisionar un bucket S3", "no encuentro el dueño del servicio X").
. **Ranking por severidad × frecuencia**. Elige la fricción top.
. **Construye solo el camino feliz** para esa fricción. Sin generalizar, sin frameworks, sin abstracciones prematuras.
. **Mide uso real**. ¿Cuántos developers la usaron esta semana? Si < 30%, vuelve al paso 1.
. **Pregunta a esos 30%** qué fricción resolver después. Vuelve al paso 1.

humor::
Construir un MVP es como servir el primer plato de un menú. Si nadie lo pide, no es que el menú esté mal diseñado: es que el primer plato no resuelve un hambre real. El error es seguir cocinando en lugar de preguntar al cliente qué tiene hambre.

==== Caso real: Spotify

Spotify no lanzó Backstage como "plataforma completa" en 2020. Lanzó el Software Catalog con tres features: ver servicios, ver owners, ver docs. Los developers lo usaron porque resolvía el problema #1 (¿quién es el dueño del servicio X?). Las features vinieron después, basadas en uso real.

Hoy tienen 200+ plugins, pero empezaron con **tres páginas web**.

=== Patrón 3: Self-Service First

Si un developer necesita pedir un ticket, abrir un Slack, o esperar a alguien para hacer algo, **no es self-service**. Es un help desk con mejor branding.

==== El test del café

NOTE::
**Analogía**: en una cafetería moderna, pides tu café en una tablet, lo pagas con tarjeta, y te lo llevas. Nadie te cobra en una ventanilla después. Si tu plataforma tiene una "ventanilla de tickets" para provisionar un namespace de Kubernetes, **es una cafetería con ventanilla**. No es moderna.

==== Self-service real vs. aparente

[cols="1,3", options="header"]
|===
| Tarea | Apparent self-service | Real self-service

| Crear servicio
| "Pulsa este botón y rellena el form" → ticket
| Pulsa el botón y 30 segundos después tienes repo + CI + namespace + catalog entity

| Provisionar bucket
| "Solicita en el portal" → ticket → espera 2 días
| `aws s3 mb` + IAM + monitoreo automáticos, sin tickets

| Rotar secreto
| "Abre ticket" → ticket → espera
| Script diario automatizado que rota y notifica
|===

WARNING::
**Red flag**: si tus métricas incluyen "tiempo medio de respuesta a tickets de plataforma", tienes un help desk. La métrica debería ser "tiempo medio de self-service" y debería tenderer a cero.

=== Patrón 4: Golden Path, no Golden Cage

Un **golden path** es el camino recomendado para una tarea común. Una **golden cage** es cuando solo existe ese camino y los developers no pueden salir.

==== Diseño correcto

[source,yaml]
----
# Golden path: crear un servicio
- Repo con plantilla (Scaffolder)
- CI configurada (GitHub Actions)
- Catalog entity registrada
- Namespace de Kubernetes
- Secrets provisionados
- Alertas configuradas

# Pero el developer PUEDE:
- Crear el repo manualmente sin pasar por el template
- Usar un nombre de namespace no estándar (con un PR que lo justifique)
- Modificar el Dockerfile generado
- No usar la plantilla CI si su equipo tiene una propia
----

==== Diseño incorrecto (cage)

[source,yaml]
----
# "Golden cage": el developer NO PUEDE
- Crear un servicio sin pasar por el Scaffolder (política enforced)
- Usar un namespace no listado en el catálogo
- Modificar el Dockerfile sin un PR aprobado por security
- No usar la plantilla CI (la build falla)
----

TIP::
**Regla de oro**: golden path es la recomendación. Si un developer elige un camino distinto, el equipo de plataforma debe preguntar **por qué** y mejorar el path. Si el golden path es realmente el mejor, los developers lo eligen voluntariamente. Si hay que forzarlo, el path no es bueno.

=== Patrón 5: Cognitive Load Reduction

El argumento más fuerte a favor de una IDP: **reduce la carga cognitiva** de un developer. No le hagas memorizar 20 pasos; dale una pantalla y un botón.

==== Las 5 cosas que un developer NO debería tener que recordar

NOTE::
.5 preguntas que un developer hace cada día (y que la plataforma debería responder)
  • ¿Dónde está el código del servicio X?

  • ¿Quién es el dueño? (y cómo lo contacto)

  • ¿Cómo deployo un cambio?

  • ¿Por qué el último deploy falló?

  • ¿Qué servicios dependen del mío? (y al revés)

Si tu plataforma no contesta alguna de estas en menos de 3 clicks, no es una plataforma: es un proyecto. El equipo de plataforma debe medir "tiempo medio para encontrar X" y trabajar para bajarlo a segundos.

==== Métricas concretas

[source,typescript]
----
// ¿Cómo medirlo?
const metrics = {
  'time_to_find_service': {
    description: 'Tiempo desde "¿dónde está X?" hasta el link del repo',
    target: '< 5 segundos',
    measurement: 'analytics desde el search del catalog',
  },
  'time_to_find_owner': {
    description: 'Tiempo desde "¿quién es el dueño?" hasta el contacto',
    target: '< 10 segundos',
    measurement: 'click en el nombre del owner → Slack/email',
  },
  'time_to_first_deploy': {
    description: 'Tiempo desde "necesito deployar" hasta deploy exitoso',
    target: '< 30 minutos',
    measurement: 'Scaffolder task duration + deploy duration',
  },
};
----

=== Patrón 6: Feedback Loops Continuos

Una plataforma sin feedback loop es como cocinar sin probar la comida: puedes seguir años sin saber si está buena.

==== Los 4 feedback loops que necesitas

[cols="1,3", options="header"]
|===
| Loop | Qué mide | Cómo actuar

| **User research**
| ¿Qué fricción tienen los developers AHORA?
| Monthly: 5 entrevistas + survey

| **Adoption metrics**
| ¿Cuántos developers usan la plataforma?
| Weekly: DAU, MAU, % de equipos activos

| **Quality metrics**
| ¿Funciona bien? ¿Es rápida? ¿Tiene bugs?
| Daily: MTTR de incidencias, latencia p95

| **Value metrics**
| ¿Está cumpliendo los objetivos de negocio?
| Quarterly: onboarding time, deploy frequency, MTTR global
|===
| ¿Está cumpliendo los objetivos de negocio?
| Quarterly: onboarding time, deploy frequency, MTTR global
|===

==== Caso real: Spotify

Spotify reporta que **50% de sus empleados usan Backstage mensualmente**, y la mayoría de engineers lo usan diariamente. Esa es la métrica de adopción que justifica la inversión.

(Ver :xref:cap-23-buenas-practicas-platform-engineering[cap-23] para más sobre métricas.)

=== Patrón 7: Treating Plugins as Products

Cada plugin de Backstage debería tratarse como un **producto independiente** con:
* Un owner claro
* Una definición de "done"
* Una definición de "users" (¿quién lo usa?)
* Una versión con semver
* Documentación y onboarding

humor::
Un plugin sin owner es como una receta sin cocinero: la escribió alguien que ya no está, nadie la mantiene, y la primera vez que falla, todo el restaurante se para. Si tu plugin no tiene un humano responsable, **no es un plugin**: es un archivo huérfano.

==== Patrón Spotify: "Contributing teams own their plugins"

NOTE::
El caso Spotify (de :xref:cap-22-casos-de-estudio-famosos[cap-22]):

> "Inside Spotify we have a team that owns our CI platform. They not only maintain the pipelines and build servers, but also expose their product in Backstage through a plugin. Since they also maintain their own API, they can improve their product by iterating on API and UI in lockstep."

Cada equipo dueño de su **propio producto** (CI, monitoring, secrets) crea y mantiene **su propio plugin**. El equipo de plataforma solo provee el "shell" (la app, el catalog, los mecanismos comunes).

**Lección**: no centralices la creación de plugins en el equipo de plataforma. Empodera a cada equipo de producto a crear el suyo. El equipo de plataforma solo provee guías, lint, y herramientas comunes.

=== Patrón 8: Embedded Rotations (no Skill Concentration Trap)

WARNING::
**Anti-pattern (Skill Concentration Trap)**: el equipo de plataforma recluta a todos los senior engineers. Los product teams pierden expertise. Resultado: el equipo de plataforma se convierte en cuello de botella y los product teams se vuelven "consumidores pasivos".

**Patrón (Embedded Rotations)**: rotar developers de product teams al equipo de plataforma, y de plataforma a product teams. 1 sprint cada 6 meses.

Beneficios:
* Los platform engineers entienden el dolor real de los developers.
* Los product teams conocen la plataforma por dentro, no la temen.
* Se distribuye el conocimiento: si un platform engineer se va, hay 5 personas que pueden mantener su código.

TIP::
Spotify practica esto: cada nuevo Backstage engineer pasa su primer mes en un product team, y cada platform engineer rota 1 sprint al año a un product team. El resultado: cuando un developer reporta un bug, el platform engineer que lo recibe ya sabe qué hace ese equipo.

=== Resumen

* **Platform as a Product**: la plataforma es un producto, los developers son clientes.
* **MVP primero**: resuelve UNA fricción real, mide uso, itera.
* **Self-Service First**: si requiere un ticket, no es plataforma.
* **Golden Path, no Golden Cage**: recomienda, no fuerces.
* **Cognitive Load Reduction**: 5 preguntas que la plataforma debe responder en segundos.
* **Feedback Loops**: user research, adopción, calidad, valor.
* **Plugins as Products**: cada plugin con owner, versión, y "users" definidos.
* **Embedded Rotations**: distribuir conocimiento, evitar el skill concentration trap.

=== Glosario del capítulo

[glossary]
Platform as a Product (PaaP):: Mentalidad de tratar la plataforma como un producto con clientes, métricas y roadmap.
Minimum Viable Platform (MVP):: La fricción más dolorosa resuelta en 6-8 semanas, no la plataforma completa.
Self-service:: Capacidad de un developer de hacer una tarea sin intervención humana.
Golden path:: Camino recomendado para una tarea común. Recomendado, no forzado.
Golden cage:: Anti-pattern donde solo existe un camino y se fuerza a los developers.
Cognitive load:: Esfuerzo mental requerido para usar una herramienta. La plataforma debe minimizarlo.
Embedded rotation:: Práctica de rotar developers entre platform team y product teams.
Skill concentration trap:: Anti-pattern: todos los senior engineers en platform team, los product teams pierden expertise.

=== Próximo capítulo

xref:cap-22-casos-de-estudio-famosos[Capítulo 22 — Casos de estudio: lo que aprendimos de Spotify, Netflix, American Airlines y más] — qué hicieron bien, qué hicieron mal, y qué puedes copiar directamente.

:leveloffset!:

:leveloffset: +1

== Casos de estudio: lo que aprendimos de los que ya lo hicieron
:chapter: cap-22
:part: parte-7-patrones
:order: 22

[chapter-meta]
====
*Tiempo de lectura*: 22 min · *Itinerarios*: cocinero jefe, CTO, consultor. Lee :xref:cap-21-patrones-de-implementacion[cap-21] antes.
====

NOTE::
.Objetivos del capítulo

Al terminar este capítulo vas a poder:

  • Conocer cómo organizaciones grandes han implementado Backstage/IDP en producción.

  • Distinguir entre lo que funcionó, lo que falló y por qué.

  • Identificar patrones de adopción exitosos en tu propia organización.

  • Aprender de los errores ajenos sin tener que cometerlos.

  • Construir un business case para tu plataforma citando casos reales.

===== La verdad sobre los casos de estudio

Los casos de estudio se cuentan de dos formas: la versión oficial ("lo hicimos y fue un éxito") y la versión real ("lo hicimos, fue un desastre al principio, sobrevivimos por X, Y, Z"). Este capítulo es la segunda versión.

humor

Un caso de estudio oficial es como la foto de un plato en un menú: el cocinero eligió la mejor foto entre 20 intentos. Un caso de estudio real es el desorden de la cocina: la salsa que se quemó, el comensal que devolvió el plato, el nuevo cocinero que no sabe dónde está la sal. Aprendes más del desorden que de la foto.

NOTE

Las cifras que verás vienen de fuentes públicas (Roadmap de Backstage, TechCrunch, InfoWorld, podcasts, blogs de empresa). Donde una métrica sea privada o estimada, lo decimos explícitamente. No inventamos números: el rigor de este libro es tu mejor defensa cuando presentes a tu CTO.

===== Caso 1: Spotify — el inventor del género

Spotify no es un "usuario temprano" de Backstage: es el inventor. La historia comienza en 2016 con un problema concreto: 800+ microservices, sin catálogo, sin owners claros.

===== El problema original

NOTE

Spotify en 2016:

  • 800+ servicios en producción

  • 4.000+ ingenieros

  • Sin forma de responder "¿quién es el dueño del servicio X?" sin mandar un Slack a un canal con 800 personas

  • Sin forma de saber qué servicios dependían de otros

  • Onboarding de un nuevo engineer: 4-6 semanas solo para entender la arquitectura

humor

Imagina 800 servicios sin mapa. Cada vez que un developer preguntaba "¿quién mantiene el servicio de pagos?", alguien tenía que recordar que era María, y si María se había ido de vacaciones, nadie más lo sabía. Era como un restaurante con 800 recetas, sin índice, y cada cocinero solo conocía la suya.

===== La decisión: 2016-2018, "no es proyecto, es producto"

Spotify hizo algo que la mayoría de empresas evita: trataron la plataforma como un producto desde el día uno. El primer equipo fue un squad dedicado de 4 personas que:

  1. Construyeron el Software Catalog como un servicio web simple (no un wiki, no un spreadsheet).

  2. Lo abrieron a 50 ingenieros early adopters.

  3. Escucharon feedback durante 2 meses antes de añadir features.

  4. Solo cuando los 50 lo usaban diariamente, lo expandieron a todo el equipo.

===== La escala: 2018-2020, "backstage de todos"

Para 2018, Backstage era obligatorio en Spotify. Para 2020 (cuando lo donaron a CNCF), tenían:

  • 200+ plugins internos creados por equipos de producto (CI, monitoring, secrets, etc).

  • TechDocs adoptada para toda la documentación técnica.

  • Software Templates que provisionan el 90% de los servicios nuevos.

  • 50% de los empleados activos mensualmente en Backstage.

    NOTE

    Cifras de Spotify (públicas):

  • 50% MAU entre todos los Spotifiers (no solo engineers).

  • Tiempo hasta que un nuevo engineer mergea su 10º PR: bajó 55% dos años después de Backstage.

  • 200+ plugins internos (fuente: webinar Spotify Oct 2025).

  • >3.400 organizaciones fuera de Spotify usan Backstage (Roadmap 2026).

# Lo que copiamos

  • Tratar Backstage como producto desde el día uno. No como infraestructura.

  • MVP antes de features. Software Catalog solo, sin extras.

  • Plugins distribuidos. Cada equipo de producto hace el suyo.

  • Métricas de adopción, no de tickets cerrados.

# Lo que NO copiamos

  • El tamaño de Spotify. Si tienes 100 ingenieros, 200 plugins es overkill. Empieza con 10.

  • La cultura de "todos los engineers experimentados pueden rotar al platform team". Requiere masa crítica.

===== Caso 2: Dynatrace — observabilidad en el portal

Dynatrace adoptó Backstage para integrar observabilidad y seguridad en tiempo real dentro del portal. Su caso es interesante porque Dynatrace ya tenía una plataforma de observabilidad: el reto era conectar lo que ya tenían con Backstage.

# Lo que hicieron

NOTE

Plugins custom de Dynatrace en su Backstage:

  • dynatrace-topology: muestra el grafo de servicios de Dynatrace directamente en la pestaña de overview de cada componente del catalog.

  • dynatrace-incidents: lista de incidentes activos con link directo a la vista de Dynatrace.

  • dynatrace-security: hallazgos de seguridad por servicio, con severidad y tiempo de exposición.

Por qué importó: los developers no tenían que salir del portal para ver "mi servicio está roto" o "mi servicio tiene una vulnerabilidad crítica". El portal se convirtió en el single pane of glass.

humor

Dynatrace demostró que un portal no vale solo por lo que trae built-in, sino por lo que conecta. Su Backstage es un índice: el catálogo les dice qué servicios existen, Dynatrace les dice cómo están. La unión de los dos es 10× más valiosa que cada uno por separado.

# Métricas reportadas

  • Mejora en "service visibility" y "ownership clarity" (métricas cualitativas de DevOps feedback loops).

  • Reducción de context-switching entre herramientas (cuantificado en surveys internos).

# Lo que aprendemos

  • Plugins valiosos no son los más complejos, son los que responden una pregunta. "¿Está roto mi servicio?" es la pregunta más respondida.

  • No reimplementes funcionalidades que ya tienes en otro sistema. Conecta, no clones.

  • El portal no es un wiki: es un hub. Los datos viven donde están bien cuidados; el portal solo los muestra.

===== Caso 3: American Airlines — escala masiva con datos legacy

American Airlines es uno de los adoption cases más interesantes porque combina Backstage con sistemas legacy de 30+ años. Un portal moderno en una empresa con mainframes es siempre delicado.

# El problema

  • 1.000+ developers

  • Mezcla de Java moderno y COBOL de los 80s

  • Catalogar todos los servicios manualmente era imposible

  • "Onboarding" de un nuevo developer tardaba 3+ meses

# La solución: Backstage + descubrimiento automático

NOTE

Plugins clave de American Airlines:

  • legacy-system-bridge: cruza el catalog de Backstage con un inventario de mainframes, exponiendo la "cara moderna" de cada sistema legacy.

  • auto-discovery-bot: escanea repos internos cada 24h, identifica servicios no catalogados, y abre PRs automáticamente con el catalog-info.yaml.

  • onboarding-journey: tour guiado de 7 días para nuevos developers, midiendo el progreso en cada sprint.

# Métricas reportadas

  • Onboarding time bajó de 3 meses a 3 semanas (estimación pública en podcast PlatformCon 2024).

  • 85% de servicios catalogados en 6 meses (vs objetivo inicial de 50%).

  • Tiempo de búsqueda de "quién es el dueño" bajó de 1 hora a 5 minutos (medido en producción).

# Lo que aprendemos

  • Auto-discovery es crítico en organizaciones con >500 servicios. No puedes pedirle a 50 equipos que escriban su catalog-info.yaml a mano.

  • El onboarding es un journey, no un momento. Una tour guiado de 7 días con milestones > un "Welcome to Backstage" email.

  • Los legacy systems necesitan plugins custom, no plugins oficiales. El caso de uso no es "crear un servicio en Kubernetes", es "entender un sistema que lleva 30 años evolucionando".

===== Caso 4: JPMorgan — compliance y auditoría

JPMorgan adoptó Backstage en un contexto muy regulado. El reto era demostrar compliance sin paralizar a los developers.

# El enfoque: "compliance as code"

NOTE

Plugins de compliance de JPMorgan:

  • soc2-validator: cada PR a un servicio valida automáticamente los controles SOC2.

  • audit-log-aggregator: agrega los eventos del Permission Framework a un SIEM corporativo (Splunk).

  • data-classification-enforcer: impide que un servicio sin data-classification: pii acceda a bases de datos marcadas como PII.

humor

JPMorgan demostró que compliance y velocidad no son opuestos: si el compliance está automatizado en el golden path, los developers cumplen sin pensar. El anti-pattern es compliance como un portal separado al que el developer va "cuando se acuerda" (o sea, nunca).

# Lo que aprendemos

  • Compliance se automatiza, no se documenta. Un check de 30 segundos en el PR es más efectivo que 30 PDFs.

  • El Permission Framework es la pieza clave de auditoría. Cada decisión de "puede X ver Y" se loguea y exporta a un SIEM.

  • Data classification en el catalog evita incidentes. Saber qué servicio toca qué datos es el primer paso de GDPR/SOC2.

===== Caso 5: LinkedIn, Twilio, Unity, Splunk — adopción sin fanfare

Estos cuatro casos comparten un patrón: adoptaron Backstage sin hacer mucho ruido público, y reportan resultados similares: 60-80% de servicios catalogados, ~50% MAU entre engineers.

# Lo que tienen en común

NOTE

.Patrón típico de "adopción silenciosa"

. Empezaron con un MVP (catalog + 2-3 plugins oficiales)
. Invitaron a 2-3 equipos early adopters
. Dejaron que los equipos early adopters evangelizaran orgánicamente
. No forzaron adopción. Esperaron a que el golden path fuera claramente mejor que la alternativa
. Miden adopción, no tickets
humor

LinkedIn, Twilio, Unity y Splunk son la prueba de que "construirlo y esperar" no funciona pero construirlo y dejarlo crecer orgánicamente sí. La diferencia: tener un MVP real, no una promesa. Si tu primer día solo tiene catalog + CI, no hay nada que evangelizar. Si tiene catalog + CI + secrets + monitoring, hay 4 cosas que se explican solas.

# Lo que aprendemos

  • Adopción silenciosa es el patrón dominante. La mayoría de empresas que adoptan Backstage no lo anuncia con un blog.

  • El evangelismo orgánico > el mandate top-down. Un equipo que usa Backstage y le cuenta a su vecino vale más que 10 emails del CTO.

  • Medir MAU, no "usuarios registrados". Los developers votan con sus pies.

===== Caso 6: IKEA — empresa no-tech adoptando platform engineering

IKEA es el caso más sorprendente: una empresa de muebles, no de tecnología, con un platform team de 7 personas sirviendo a 800+ developers.

# El reto: IDP en una empresa de retail

  • 800+ developers internos

  • Equipos distribuidos (Suecia, Holanda, India)

  • Mezcla de Java, Node.js, .NET

  • Catálogo inicial: 0 servicios. Tenían que crearlo todo desde cero.

# La estrategia: 6 meses, 3 plugins, 1 métrica

NOTE

Plan de IKEA (publicado en PlatformCon 2024):

  • Mes 1-2: catalog + plugin de GitHub discovery (auto-detecta servicios en repos)

  • Mes 3-4: agregar TechDocs (los developers podían tener docs por primera vez en años)

  • Mes 5-6: software templates (primer golden path: crear un servicio Node.js)

  • Métrica única: % de servicios catalogados. Empezaron en 0%, llegaron a 65% en 6 meses.

# Lo que aprendemos

  • No necesitas un platform team de 50 personas para empezar. Con 7 puedes llegar a 65% de adopción si haces MVP-first.

  • Auto-discovery es el primer plugin que necesitas. Sin él, catalogar es un proyecto paralelo eterno.

  • TechDocs es el plugin que más rápido aporta valor. Los developers lo adoptan porque ellos lo mantienen, no porque alguien se lo pida.

===== Caso 7: lo que NO funcionó (anti-patterns documentados)

Además de los casos públicos, hay lecciones de empresas que no se llaman pero cometieron errores conocidos. Las recogemos del paper "9 Platform Engineering Anti-Patterns" de Jellyfish y de InfoWorld.

# Anti-pattern 1: Field of Dreams

"Lo construimos y vinieron". No vinieron.

NOTE

Síntomas:

  • 12+ meses de desarrollo

  • Lanzamiento con todas las features

  • 5% de adopción en 6 meses

  • El equipo de plataforma se quema buscando "cómo evangelizar"

Causa: se construyó sin user research. Asumieron qué necesitan los developers en lugar de preguntarles.

Fix: MVP primero, user research continuo, iterar por adopción real.

# Anti-pattern 2: Mandated Adoption

"Todos los servicios DEBEN usar Backstage desde el 1 de enero". Mandato del CTO.

NOTE

Síntomas:

  • Catalog inflado con entidades "de papel" (rellenas a mano, sin uso real)

  • Software Templates que se llenan a medias y crean servicios rotos

  • Developers que esquivan el golden path en secreto

  • El 80% del uso es para evitar la penalización, no porque aporte valor

Causa: la plataforma no era la mejor opción. El mandato la fuerza pero no la mejora.

Fix: mejora la plataforma hasta que elegirla sea lo obvio. Si necesitas forzar, algo está mal.

# Anti-pattern 3: Skill Concentration Trap

Todos los senior engineers al platform team. Los product teams quedan sin expertise.

NOTE

Síntomas:

  • Platform team de 20 personas, product teams de 5

  • Cualquier cambio en product team requiere "consultar a platform"

  • Platform team saturado de tickets

  • "Si el platform team se va, todo se rompe"

Causa: "si es importante, ponle a los mejores". Olvidan que la plataforma es para los product teams, no al revés.

Fix: rotaciones, embedded engineers, "raising the bar" no "centralizing the bar".

# Anti-pattern 4: Building a Portal instead of a Platform

Un portal bonito con 50 botones. Pero por debajo, son solo redirecciones a otros sistemas.

NOTE

Síntomas:

  • 30+ plugins que son thin wrappers

  • "Si quitas la UI, todo se sigue usando desde la línea de comandos"

  • El portal añade un click extra sin añadir valor

  • Los developers evitan el portal

Causa: confusión entre portal y plataforma. El portal es la UI; la plataforma es el conjunto de servicios, herramientas y políticas.

Fix: el portal orquesta las herramientas, no las reemplaza. Cada integración debe simplificar un flujo existente, no añadir un paso.

# Anti-pattern 5: Tool Aggregation without Real Integration

"Tengo Jenkins, GitLab, Datadog, PagerDuty. Los pongo todos en el portal y voilà, plataforma".

NOTE

Síntomas:

  • Cada plugin abre una pestaña nueva que es la herramienta original con CSS diferente

  • No hay correlación: si Datadog dice "picos de CPU", el portal no muestra el deploy que lo causó

  • Los developers tienen que abrir 4 pestañas para entender un problema

Causa: confundir "tener muchas herramientas" con "tener una plataforma".

Fix: integración real. Si una alerta de Datadog no enlaza al último deploy del servicio afectado, no es integración. Es agregación.

===== Lo que todos los casos exitosos tienen en común

Después de revisar 7+ casos públicos, hay 5 invariantes que se repiten en todos los adoption cases exitosos:

NOTE

.Los 5 invariantes del éxito

. **MVP antes de features**. Spotify, IKEA, LinkedIn, Twilio: todos empezaron con catalog + 1-3 plugins.
. **Plugin ownership distribuido**. Cada equipo dueño de su producto, dueño de su plugin.
. **Métricas de adopción, no de output**. DAU/MAU, onboarding time, deploy frequency. No "tickets cerrados" ni "features shipped".
. **Compliance/security automatizados en el golden path**. JPMorgan, American Airlines: el golden path ES la auditoría, no un check al final.
. **Embedded rotations y evangelismo orgánico**. Sin mandate, sin "sprint de adopción". Crecimiento de base.

===== Resumen

  • Spotify: inventor, 200+ plugins, 50% MAU, MVP-first.

  • Dynatrace: conectar el portal a lo que ya tenías (observabilidad).

  • American Airlines: auto-discovery + onboarding journey de 7 días.

  • JPMorgan: compliance as code en el golden path.

  • LinkedIn/Twilio/Unity/Splunk: adopción silenciosa, evangelismo orgánico.

  • IKEA: 7 personas bastan para 65% de adopción.

  • Anti-patterns: Field of Dreams, Mandated Adoption, Skill Concentration, Portal over Platform, Tool Aggregation.

===== Glosario del capítulo

Adopción silenciosa

Patrón de empresas que adoptan platform engineering sin grandes anuncios, con evangelismo orgánico.

Auto-discovery

Plugin que escanea repos y crea catalog entities automáticamente.

Compliance as code

Implementar controles de seguridad/compliance como código en el golden path, no como gates manuales.

Embedded rotation

Práctica de mover developers entre platform team y product teams.

Field of Dreams fallacy

Construir una plataforma completa sin feedback y esperar que los developers la adopten.

Golden cage

Anti-pattern donde solo existe un camino y se fuerza a los developers a usarlo.

Onboarding journey

Tour guiado de varios días con milestones, no un momento único.

Self-service

Capacidad del developer de hacer una tarea sin intervención humana.

Skill concentration trap

Anti-pattern: senior engineers centralizados en platform team.

===== Próximo capítulo

Capítulo 23 — Buenas prácticas de platform engineering — cómo aplicar DORA, SPACE y métricas de golden path, y cómo construir un business case defendible.

== Buenas prácticas de platform engineering: medir lo que importa :chapter: cap-23 :part: parte-7-patrones :order: 23

Tiempo de lectura: 25 min · Itinerarios: cocinero jefe, CTO, consultor. Lee :cap-21 y :cap-22 antes.

NOTE
.Objetivos del capítulo

Al terminar este capítulo vas a poder:

  • Implementar las 4 métricas DORA y entender qué miden (y qué no).

  • Aplicar SPACE y DX metrics para complementar DORA.

  • Construir un "platform health" dashboard con señales adelantadas.

  • Diseñar un golden path medible: cada template con su KPI de éxito.

  • Hacer un business case defendible con datos de la industria.

  • Saber cuándo una métrica es buena y cuándo es vanity.

// evidence: cl-dora-metrics (4 métricas oficiales), cl-space-framework, cl-developer-experience

===== El problema con las métricas de plataforma

Medir una plataforma es difícil porque **lo que importa no es directamente observable**:

* ¿La plataforma ayuda a los developers? No puedes medir "felicidad" directamente.
* ¿Reduce el time-to-market? El time-to-market depende de 50 factores, no solo de la plataforma.
* ¿Es rentable? Calcular el ROI de un proyecto interno es siempre opinable.

[humor]

humor

Las métricas se agrupan en tres categorías: . Output: cuántas features, tickets, despliegues produce la plataforma. . Outcome: qué cambia en la organización gracias a la plataforma. . Health: señales adelantadas que predicen problemas.

NOTE

===== DORA: las 4 métricas de DevOps performance

DORA (DevOps Research and Assessment) es el estándar de la industria para medir performance de entrega de software. Lleva 10+ años midiendo organizaciones de todo tamaño y encontró que **4 métricas** predicen el rendimiento de una organización.

NOTE::
Las 4 métricas DORA (fuente: DORA State of DevOps Report)
. **Deployment Frequency**: ¿con qué frecuencia desplegamos a producción?
. **Lead Time for Changes**: ¿cuánto tarda un commit en llegar a producción?
. **Change Failure Rate**: ¿qué porcentaje de despliegues rompen algo?
. **Time to Restore Service (MTTR)**: ¿cuánto tardamos en recuperarnos de un fallo?

Estas 4 métricas separan a las organizaciones en 4 niveles: **Elite, High, Medium, Low**. La diferencia entre Elite y Low puede ser 200× en deployment frequency y 6,000× en MTTR.

===== Cómo se relacionan con una IDP

Métrica DORA Cómo ayuda una IDP Métrica proxy en Backstage

Deployment Frequency

Templates + CI automatizada = despliegues más rápidos

scaffolder.task.completed con duración

Lead Time for Changes

Pre-commit hooks, code review desde el portal

time from PR open → deployed (custom)

Change Failure Rate

Scorecards en golden path = menos errores

deploy.failed / deploy.total (de CI)

Time to Restore

Runbooks en TechDocs, on-call en portal

incident.acknowledged → resolved (custom)

**No midas DORA como meta de la plataforma**. Mídelas a nivel de equipo/organización. La plataforma es una de las muchas variables que afectan a DORA. Si "el equipo X mejoró su deployment frequency" después de adoptar un template, **es una correlación, no una causalidad**. Atribuir todo a la plataforma es el error más común.

===== SPACE: el framework que complementa a DORA

DORA mide performance de entrega. SPACE mide productividad y bienestar de los developers. Son complementarias: DORA te dice si entregas rápido, SPACE te dice si tus developers están sanos (y por lo tanto, van a seguir entregando).

NOTE
.Las 5 dimensiones de SPACE (Storey et al., 2021)
  1. Satisfaction & well-being: ¿están los developers contentos con su trabajo y herramientas?

  2. Performance: ¿el output que producen tiene calidad? (no cantidad)

  3. Activity: ¿qué hacen? (commits, PRs, code reviews) — pero con cuidado, no es lo que importa

  4. Communication & collaboration: ¿cómo se coordinan? ¿con cuántos hand-offs?

  5. Efficiency & flow: ¿pueden completar trabajo sin interrupciones? ¿el flow es continuo?

[humor]

humor

===== Cómo implementar SPACE en una IDP

// SPACE satisfaction: ¿están los developers contentos con la plataforma?
class PlatformSatisfaction {
  // Quarterly survey
  collectSurvey(): Promise<Score> {
    // 1 pregunta: "¿Cómo de fluida es la plataforma?" (1-5)
    // Complementada con: "¿Qué fricción te ha quitado más tiempo este mes?"
  }
}

// SPACE performance: ¿el output tiene calidad?
// DORA ya cubre delivery performance, pero hay que mirar quality
class PlatformOutputQuality {
  // Medir % de PRs revertidos en 30 días
  // Medir % de deploys con incident subsecuente
}

// SPACE activity: ¿qué hacen los developers con la plataforma?
class PlatformActivity {
  // DAU/MAU del portal
  // Frecuencia de uso de cada plugin
  // Tiempo medio en el portal por sesión
}

// SPACE communication: ¿cuántos hand-offs?
// Medir el "approval chain" de cada deploy
// Pregunta: ¿cuántas personas necesitan aprobar antes de merge?
class PlatformCommunication {
  // PRs con >3 reviewers = muchos hand-offs
  // Tickets que cruzan >2 equipos
}

// SPACE efficiency: ¿hay flow?
class PlatformEfficiency {
  // Tiempo desde "crear un servicio" hasta "primer deploy"
  // Tasa de abandono de Software Templates
}

===== Implementación práctica: el "platform health scorecard"

# platform-health-scorecard.yml
# Se evalúa mensualmente con datos reales

metrics:
  dora:
    deployment_frequency:
      target: "> 1/día para servicios tier-1"
      measurement: "Promedio de los últimos 30 días"
    lead_time:
      target: "< 24h para PRs pequeños"
      measurement: "PR open  deployed"
    change_failure_rate:
      target: "< 15%"
      measurement: "deploys que requieren rollback"
    mttr:
      target: "< 1h para incidentes tier-1"
      measurement: "incident ack  resolved"

  space:
    satisfaction:
      target: "> 4.0/5 en survey trimestral"
      measurement: "Pregunta Likert 1-5"
    performance:
      target: "< 5% de PRs revertidos en 30 días"
      measurement: "PRs con revert en 30 días"
    activity:
      target: "> 50% de developers activos semanalmente"
      measurement: "DAU/MAU del portal"
    communication:
      target: "PRs con < 3 reviewers medianamente"
      measurement: "Distribución de reviewer count"
    efficiency:
      target: "> 80% de golden paths completados"
      measurement: "% de templates usados vs abandonados"

  health:
    api_latency_p95:
      target: "< 500ms"
    error_rate:
      target: "< 0.1%"
    catalog_freshness:
      target: "> 95% de entidades actualizadas en 7 días"
.....


===== DX (Developer Experience): las métricas que SÍ puedes mover

DX metrics (de la consultora https://getdx.com/[GetDX] y https://www.gitlab.com/[GitLab]) son operativas: puedes cambiarlas en una semana con un cambio de plataforma.

NOTE::
.....

.Las 5 métricas DX que cambian con tu IDP
.....

. **Time to first commit** (para nuevos developers en un servicio)
. **Time to first deploy** (de commit a producción)
. **PR review time** (de PR abierto a merge)
. **Build time** (CI duration)
. **Friction score** (medido por surveys, "¿qué te retrasó esta semana?")
.....


===== Implementación: el "Developer friction survey" semanal

[source,typescript]

class FrictionSurvey { // Cada lunes a las 10am, pregunta a 10 developers aleatorios askWeekly(): Promise<FrictionData> { const questions = [ '¿Qué fricción te retrasó más esta semana?', '¿Cuántas veces al día te cambiaste de herramienta (Slack, IDE, portal, CI)?', 'Si pudieras mejorar una cosa de la plataforma, ¿cuál sería?', ]; return this.sendToRandomDevelopers(questions); }

  // Tag cada respuesta con tags predefinidos para análisis
  tagResponse(response: string): Tag[] {
    if (response.includes('buscar')) return ['catalog', 'discovery'];
    if (response.includes('CI') || response.includes('build')) return ['ci', 'speed'];
    if (response.includes('deploy')) return ['deploy', 'scaffolder'];
    if (response.includes('permiso') || response.includes('auth')) return ['auth', 'permissions'];
    return ['other'];
  }
}
[TIP]
.....

TIP

===== Golden paths medibles: el KPI por template

Un golden path sin KPI es como un plato del menú sin precio: nadie sabe si vale la pena pedirlo. Cada template debería tener un **KPI de éxito** medido mensualmente.

NOTE::
.....

.Plantilla de KPI por golden path
.....

* **Nombre**: crear-servicio-nodejs
* **Owner**: platform/team-x
* **KPI primario**: % de servicios nuevos que usan el template
  * Target: > 80%
  * Source: catalog: `metadata.annotations.backstage.io/created-by`
* **KPI secundario**: tiempo desde "click en crear" hasta "primer deploy"
  * Target: < 30 minutos
  * Source: events de scaffolder + CI
* **KPI de salud**: % de templates que terminan sin error
  * Target: > 90%
  * Source: scaffolder.task.failed / scaffolder.task.completed
* **Frecuencia de revisión**: mensual
.....


===== Cómo implementar

[source,typescript]

import { createBackendModule, coreServices } from '@backstage/backend-plugin-api'; import { eventsServiceRef } from '@backstage/plugin-events-node';

export const kpiTracker = createBackendModule({ pluginId: 'scaffolder', moduleId: 'kpi-tracker', register(env) { env.registerInit({ deps: { events: eventsServiceRef, database: coreServices.database }, async init({ events, database }) { events.subscribe({ topic: 'scaffolder.task.completed', handler: async (event) ⇒ { const templateName = event.task.spec.templateInfo.entity.metadata.name; const duration = event.task.completedAt - event.task.createdAt; const success = event.task.status === 'completed';

            await database.kpis.record({
              template: templateName,
              duration,
              success,
              user: event.task.spec.user.entity.name,
              timestamp: new Date(),
            });
          },
        });
      },
    });
  },
});
[NOTE]
.....

NOTE

===== Métricas vanity: cómo detectarlas

Una métrica vanity es aquella que **parece importante pero no guía decisiones**. Si cambias la métrica y no cambias nada en la plataforma, no es útil.

NOTE::
.....

.5 señales de una métrica vanity
.....

. **No la usa nadie para tomar decisiones**. Si nadie la mira en un dashboard, no existe.
. **No tiene target concreto**. "MAU: 1000" sin contexto no dice nada.
. **No tiene owner**. Si nadie es responsable de moverla, no se mueve.
. **Mide output, no outcome**. "100 templates creados" sin saber si ayudaron a alguien.
. **No es accionable**. "Developer satisfaction" sin preguntas específicas no te dice qué cambiar.
.....


### Ejemplos de vanity vs. útil

[cols="1,1,2", options="header"]
|===
| Métrica | ¿Vanity? | Por qué

| "10.000 visitas al portal"
| Vanity
| No dice si los developers están resolviendo problemas

| "70% de servicios catalogados"
| Útil
| Te dice si la información es completa

| "99% uptime del portal"
| Útil
| Te dice si la plataforma es confiable

| "3 templates creados"
| Vanity
| "Creados" no es "usados". Mira "ejecutados por developers"

| "DAU 500 developers"
| Útil
| Te dice si hay tracción real

| "5 tickets al mes sobre problemas X"
| Útil
| Te dice si hay un problema recurrente que automatizar
|===

===== Business case: cómo vender la plataforma a tu CTO/CFO

Un buen business case tiene **3 capas**:

NOTE::
.....

.Las 3 capas del business case
.....

. **Coste**: cuánto cuesta la plataforma (team, infraestructura, mantenimiento).
. **Beneficio cuantificable**: cuántas horas/$$ ahorrados, cuántos errores evitados, cuánto más rápido se entregan features.
. **Beneficio estratégico**: posicionamiento de la empresa en el mercado, retención de talento, capacidad de innovar.
.....


### Plantilla de business case

[source,markdown]

# Business case: Internal Developer Platform (Backstage)

## Coste anual estimado - Platform team: 4 FTE × 120k€ = 480k€ - Infraestructura (Backstage HA, DB, observability): 30k€ - Plugin development: 2 FTE × 120k€ = 240k€ - Total: 750k€/año

## Beneficio cuantificable (año 1, proyección conservadora)

# Onboarding time - Antes: 3 meses × 5 nuevos devs/mes × 8k€/mes = 120k€/mes - Después: 3 semanas × 5 nuevos devs/mes × 8k€/mes = 30k€/mes - Ahorro: 90k€/mes = 1.08M€/año

# Deploy frequency - Antes: 2 deploys/servicio/semana - Después: 1 deploy/servicio/día (con golden path) - Beneficio: 5× más rápido, lo que se traduce en 200k€/año en time-to-market

# Incident reduction - 30% de incidentes vienen de configuración manual incorrecta - Golden path elimina esa causa - Ahorro: 150k€/año (estimación conservadora)

# Total beneficio: 1.43M€/año

## ROI - (1.43M - 0.75M) / 0.75M = +90% ROI - Payback period: 8 meses

## Beneficio estratégico (no cuantificable directamente) - Retención de talento: developers frustrados se van - Time-to-market para nuevos productos - Compliance automatizado (ahorra auditorías) - Posicionamiento como empleador técnico

[humor]
.....

humor

===== Resumen

* Hay 3 categorías de métricas: **output, outcome, health**. Necesitas las tres.
* **DORA** mide performance de entrega. **SPACE** mide productividad y bienestar. **DX** mide fricción operativa.
* Cada **golden path** debe tener un **KPI de éxito** con owner y target.
* **Métricas vanity** son la trampa más común. Si no guían decisiones, no valen.
* Un **business case** con números conservadores y ROI honesto es lo que aprueba un CFO.
* Spotify: 50% MAU, 200+ plugins. IKEA: 7 personas bastan para 65% de adopción.

===== Glosario del capítulo

[glossary]
DORA:: DevOps Research and Assessment. 4 métricas: deployment frequency, lead time, change failure rate, MTTR.
SPACE:: Framework de productividad developer: Satisfaction, Performance, Activity, Communication, Efficiency.
DX:: Developer Experience. Métricas operativas que cambian con la plataforma.
Vanity metric:: Métrica que parece importante pero no guía decisiones.
Golden path KPI:: Métrica de éxito asociada a un template específico.
Business case ROI:: Retorno de inversión calculado conservadoramente para justificar la plataforma.
Embedded rotation:: Práctica de rotar developers entre platform team y product teams.
Cognitive load:: Esfuerzo mental requerido para usar una herramienta.

===== Próximo capítulo

xref:cap-24-anti-patrones[Capítulo 24 — Anti-patrones: cuándo NO construir una IDP, errores de plataformización forzada, y cómo evitarlos] — la última pieza del puzzle: saber cuándo parar.

:leveloffset: 1

:leveloffset: +1

== Anti-patrones: cuándo NO construir una IDP, y cómo evitar los que sí
:chapter: cap-24
:part: parte-7-patrones
:order: 24

[chapter-meta]

Tiempo de lectura: 19 min · Itinerarios: cocinero jefe, CTO, consultor. Lee :cap-21 y :cap-22 antes.

NOTE

.Objetivos del capítulo

Al terminar este capítulo vas a poder:

* Reconocer los 9 anti-patrones más comunes de platform engineering.
* Saber cuándo NO construir una IDP (sí, hay casos donde es mala idea).
* Diagnosticar tu propio platform team: ¿estás cayendo en alguno?
* Aplicar el "test del olor" para detectar anti-patrones temprano.
* Planear una salida elegante si caíste en uno.
La verdad incómoda

No todas las organizaciones necesitan una IDP. Y de las que la necesitan, no todas están listas. Construir una plataforma en el momento equivocado es peor que no construir nada: gasta dinero, destruye confianza y deja al equipo quemado.

humor

Construir una IDP antes de tiempo es como abrir un restaurante de tres estrellas Michelin en un pueblo de 200 habitantes. Sí, la comida es excelente. Pero no hay suficientes clientes para mantenerlo abierto. Tres meses después, cierras y el pueblo dice "vaya, otro que quiso hacer algo grande y no pudo". El próximo que intente algo lo tendrá más difícil.

Este capítulo es la cara oscura de :cap-21. Si en cap-21 vimos "lo que funciona", aquí veremos "lo que mata los proyectos". Ninguno es teórico: todos vienen de casos documentados.

El "test del olor": cómo detectar anti-patrones temprano

Antes de ver cada anti-patrón, una herramienta: el test del olor (smell test). Si tu proyecto de plataforma tiene alguno de estos síntomas, estás cerca de un anti-patrón:

NOTE

.5 olores que indican anti-patrón

. **"Llevamos 8 meses y aún no hay usuarios"**. El MVP se ha convertido en un proyecto.
. **"Solo lo usa el equipo de plataforma"**. No hay tracción orgánica.
. **"El CTO lo manda usar"**. La adopción es forzada, no elegida.
. **"No tenemos métricas"** o **"medimos tickets cerrados"**. No sabes si está funcionando.
. **"Los developers se quejan de la fricción"** y nadie del platform team lo sabe. Estás escuchando solo el feedback positivo.

Si tienes 2+ de estos, para. Lee este capítulo. Decide si estás en un anti-patrón y, si lo estás, sal.

Anti-patrón 1: Field of Dreams (construir y esperar)

Nombre oficial: Field of Dreams Fallacy Origen: la película "Field of Dreams" (1989), donde un granjero construye un campo de béisbol porque "una voz le dijo que si lo construía, ellos vendrían".

humor

El platform engineer que pica código durante 12 meses en una plataforma que nadie ha pedido está en la misma posición que el granjero: trabaja mucho, gasta dinero, espera que alguien venga. Spoiler: a veces vienen, pero suelen ser inspectores de hacienda.

Síntomas
  • 12+ meses desde el primer commit del platform team

  • Lanzamiento con "todas las features listas"

  • < 10% de developers activos en Backstage tras 6 meses de lanzamiento

  • El platform team justifica la falta de adopción con "es cuestión de evangelizar más"

Causa raíz
NOTE

Construir sin user research. Asumir qué necesitan los developers en lugar de preguntarles. El team piensa "los developers necesitan X", pero cuando lanzan X, descubren que los developers querían Y, o que no querían nada porque Z (su flujo actual) ya funcionaba.

Caso real documentado

Jellyfish reporta en su paper "9 Platform Engineering Anti-Patterns" un caso donde una empresa Fortune 500 gastó 18 meses y $2.4M en una plataforma "completa" antes de hablar con un developer. Resultado: 4% de adopción, plataforma archivada en 2024.

Cómo salir
NOTE

.Plan de salida del Field of Dreams

. **Pausa todo desarrollo nuevo** durante 2-4 semanas.
. **Habla con 10 developers** que NO usan la plataforma. Pregunta qué fricción tienen. No vendas nada.
. **Construye UN fix de UNA fricción** en 2-4 semanas.
. **Mide uso real** de ese fix. Si < 30%, vuelve al paso 2.
. Si tras 3 iteraciones sigues en < 30%, considera cerrar el proyecto formalmente.
Anti-patrón 2: Mandated Adoption (adopción forzada)

Nombre oficial: Mandated Adoption Origen: cuando un CTO o VP manda usar la plataforma por decreto.

humor

"Mandated adoption" es como obligar a los clientes de un restaurante a comer un plato que no han pedido. El primer día cumplen por miedo. El segundo día protestan. El tercer día van a comer a otro lado. Y el restaurante cierra, convencido de que "la gente no sabe lo que le conviene".

Síntomas
  • Mandato del CTO: "todos los servicios DEBEN usar Backstage desde X fecha"

  • Catalog inflado con entidades "de papel" (rellenas a mano, sin uso real)

  • Software Templates que se llenan a medias y crean servicios rotos

  • Developers que esquivan el golden path en secreto (vía CLI, scripts, o nuevos repos no catalogados)

  • El 80% del uso es para evitar la penalización, no porque aporte valor

Causa raíz
NOTE

La plataforma no es la mejor opción para la mayoría de casos de uso. El mandato la fuerza, pero no la mejora. Los developers la usan por obligación, no por convicción. El día que el mandato se relaje (o que un manager nuevo lo desconozca), la adopción cae a 0.

Cómo NO hacerlo
NOTE

.Para evitar la adopción forzada

. **No midas "compliance"**. Si necesitas medir cuántos servicios están en el catalog, mides adoption.
. **Trabaja en el golden path hasta que sea la opción obvia**. Si un developer tiene que decidir entre el template y hacerlo a mano, y elige a mano, el template tiene un problema.
. **Busca a los que ya lo adoptaron y pregúntales por qué**. Esa es tu propuesta de valor real. Replica ese caso.
. **Comunica el "qué gano"**, no el "qué tienes que hacer". "Con este template, tu primer deploy es en 5 minutos en lugar de 3 días" vende; "el CTO quiere que lo uses" no.
Anti-patrón 3: Skill Concentration Trap (seniors centralizados)

Nombre oficial: Skill Concentration Trap Origen: la intuición de "pon a los mejores en lo más importante" aplicada sin pensar.

humor

El Skill Concentration Trap es como un restaurante que pone a sus tres mejores chefs en la cocina de I+D, investigando nuevos platos. ¿El resultado? Los mejores chefs cocinan en privado, los clientes siguen recibiendo lo mismo, y cuando un chef se va, el restaurante pierde tres recetas que nadie más conoce. La cocina del I+D produce, pero el comedor no nota.

Síntomas
  • Platform team de 15-20 personas, product teams de 4-5

  • Cualquier cambio en un product team requiere "consultar a platform"

  • Platform team saturado de tickets (más de 50/semana por persona)

  • "Si el platform team se va, todo se rompe"

  • Product teams no entienden qué hace la plataforma por dentro

Causa raíz
NOTE

"Si es importante, ponle a los mejores". La intuición es correcta, pero la ejecución es errónea. La plataforma es para los product teams, no al revés. Si todos los seniors están en platform, los product teams no pueden tomar decisiones técnicas informadas. Y los seniors en platform pierden contacto con el dolor real.

Cómo evitarlo
NOTE

.Receta anti-skill-concentration

. **Embedded rotations** (Spotify-style): cada developer rota 1 sprint al año a otro equipo.
. **Platform engineers de product teams**: cada product team debería tener 1 developer con experiencia en platform.
. **Documentación ejecutable**: tutoriales, no wikis. Un dev nuevo debería poder configurar el golden path en 1 día, no 2 semanas.
. **Embedded platform engineers** en product teams grandes: un platform engineer embedded 6 meses, luego rota.
Anti-patrón 4: Building a Portal instead of a Platform

Nombre oficial: Portal vs Platform Origen: confundir la UI con el sistema subyacente.

humor

Un portal sin plataforma es como un menú digital sin cocina: bonito, con fotos, pero si pides, te dicen "lo sentimos, el sistema está caído". El cliente se va y no vuelve. La próxima vez que el restaurante anuncie una webapp, pensará: "otra capa de pintura sobre el mismo desastre".

Síntomas
  • 30+ plugins que son thin wrappers de herramientas externas

  • "Si quitas la UI, todo se sigue usando desde la línea de comandos"

  • El portal añade un click extra sin añadir valor

  • Los developers evitan el portal y vuelven a su flujo anterior

  • El portal se siente como "un proyecto más" no como una herramienta

Causa raíz
NOTE

Confundir portal (la UI) con plataforma (el sistema de servicios, herramientas y políticas). El portal sin plataforma es un kiosco bonito en un parking vacío. La plataforma sin portal puede ser excelente (los developers usan CLI), pero la combinación es lo que aporta el máximo valor.

Cómo salir
NOTE

.Receta para construir plataforma, no portal

. **Pregunta "¿qué flujo existente estoy simplificando?"** para cada plugin. Si la respuesta es "ninguno", reconsidera.
. **El portal orquesta, no reemplaza**. Datadog sigue siendo Datadog; Backstage muestra la vista de Datadog en el portal.
. **Mide si la gente usa el portal O la herramienta original**. Si la herramienta original gana, el plugin no aporta valor.
. **Cierra plugins que no se usan**. Mejor 5 plugins buenos que 30 vacíos.
Anti-patrón 5: Tool Aggregation without Real Integration

Nombre oficial: Aggregator not Integrator Origen: "tengo 20 herramientas, las pongo todas en el portal, ya tengo plataforma".

humor

Tool Aggregation without Real Integration es como un camarero que te anota los pedidos de 5 restaurantes diferentes, los pone en una bandeja, y te dice "aquí tienes tu cena, de sushi, pizza, kebab, chino y gourmet en el mismo plato". Has agregado 5 cenas, pero no has integrado nada. Comes las 5 o no comes nada.

Síntomas
  • Cada plugin abre una pestaña que es la herramienta original con CSS diferente

  • No hay correlación entre señales: una alerta de Datadog no enlaza al deploy que la causó

  • Los developers tienen que abrir 4 pestañas para entender un problema

  • El platform team tiene "50 integraciones" pero ninguna profunda

Cómo evitarlo
NOTE

.5 criterios de integración real (no agregación)

. **Correlación**: una alerta de monitoring enlaza automáticamente al último deploy.
. **Contexto**: el plugin de CI muestra el owner del repo, no solo el pipeline.
. **Acción**: el plugin de incidents permite responder desde el portal, no solo ver.
. **Búsqueda**: el catalog unificado busca en todos los plugins, no solo en catalog entities.
. **Workflows**: un PR de código dispara automáticamente updates en otros plugins (scorecards, docs, etc).
Anti-patrón 6: Big Bang Launch (lanzamiento monolítico)

Nombre oficial: Big Bang Launch Origen: "lanzamos cuando todo esté listo".

humor

Big Bang Launch es como abrir un restaurante con 200 platos en el menú el día 1. Nadie sabe qué pedir, los cocineros se queman, y la mitad de los platos están mal porque no hubo iteración. El restaurante de la esquina abrió con 5 platos, los fue refinando durante 6 meses, y ahora tiene 30 platos buenos. ¿Cuál crees que sobrevive al año 3?

Síntomas
  • Lanzamiento con "todas las features listas"

  • 12-18 meses desde kickoff hasta launch

  • El día 1, 30+ features

  • Sin feedback loop: "esperaremos 3 meses para ver cómo va"

Cómo evitarlo
NOTE

.Receta anti-big-bang

. **MVP en 6-8 semanas** (ver cap-21).
. **Beta cerrada** con 5-10 developers que ya se quejan de fricciones.
. **Iteración semanal** durante los primeros 3 meses.
. **Expansión gradual** por equipo, no por fecha.
. **Feature flags** para activar/desactivar features sin deploys.
Anti-patrón 7: Platform Team as Ticket Queue (mesa de tickets)

Nombre oficial: Platform Team as Ticket Queue Origen: tratar al platform team como un help desk, no como un equipo de producto.

humor

Platform Team as Ticket Queue es como el maître de un restaurante que pasa el día anotando pedidos en una libreta: "mesa 5 quiere pasta, mesa 12 quiere vino, mesa 3 quiere hablar con el chef". Al final del día, ha escrito 80 pedidos pero no ha cocinado nada. Es trabajo, pero no es progreso.

Síntomas
  • Tickets en lugar de self-service

  • Platform team pasa más tiempo en tickets que en features

  • "Tickets cerrados" como métrica de éxito

  • Developers esperan 2+ días para tareas simples

  • No hay golden paths automatizados

Cómo salir
NOTE

.De ticket queue a equipo de producto

. **Mide "tickets creados por developer"**. Si baja, estás automatizando. Si sube, la plataforma está fallando.
. **Cierra tickets escribiendo código que los evita**, no respondiendo uno a uno.
. **Publica "tickets que NO deberías abrir"**. Lista de tareas que el platform team se niega a hacer a mano.
. **Onboarding del platform team en "pensar como producto"**: cada ticket es una feature request disfrazada.
Anti-patrón 8: "It works on my machine" (sin staging compartido)

Nombre oficial: Local-only Development Origen: developers prueban la plataforma en local, no en staging.

humor

"It works on my machine" es como un chef que prueba la paella en su cocina de casa, la encuentra perfecta, y la envía al comedor. El comedor tiene otra cocina, otra paella, otro fuego. La paella del chef es sublime; la del comedor es incomible. ¿De quién es la culpa? De quien diseñó la receta sin probar en el entorno real.

Síntomas
  • "En local funciona, no sé por qué falla en staging"

  • Tests solo pasan en local

  • No hay entorno de staging compartido

  • Developers prueban manualmente antes de mergear

  • Los golden paths tienen bugs que solo aparecen en CI/CD

Cómo evitarlo
NOTE

.Receta anti-"it works on my machine"

. **CI/CD obligatorio en cada PR** (no se puede mergear sin pasar tests).
. **Entorno de staging compartido** que refleje producción 1:1.
. **Mismas versiones de dependencias** en local, CI, staging, prod.
. **Backstage local con Docker Compose** que reproduzca el stack (en este libro lo hicimos en cap-03).
. **Tests de golden path** que se ejecutan en CI antes de cada cambio.
Anti-patrón 9: Treating Platform as Infrastructure Project

Nombre oficial: Infrastructure Project Mindset Origen: tratar la plataforma como un proyecto con fecha de fin, no como un producto vivo.

humor

Treating Platform as Infrastructure Project es como un chef que decide hacer "el menú del año", lo define el 1 de enero, y no lo cambia hasta el 31 de diciembre. Los comensales que vienen en julio encuentran un menú obsoleto: la nouvelle cuisine de enero ya pasó de moda. La cocina se quedó congelada.

Síntomas
  • "El proyecto de la plataforma termina en diciembre"

  • Platform team reducido a 2-3 personas "de mantenimiento"

  • Backlog de features "para la próxima iteración" (nunca llega)

  • Roadmap congelado durante 6 meses

  • Developers frustrados: "la plataforma no evoluciona"

Cómo evitarlo
NOTE

.De proyecto a producto (permanente)

. **Platform team permanente**, no un squad con fecha de fin.
. **Roadmap trimestral**, no anual. Revisión mensual.
. **User research continuo**: 5-10 entrevistas por mes.
. **Métricas de adopción** que guían el roadmap (no opinión de un manager).
. **"Sunset policy"**: features sin usar en 6 meses se marcan para revisión.
Cuándo NO construir una IDP

No todas las organizaciones necesitan una IDP. Construir una cuando no toca es el anti-pattern de los anti-patterns. Aquí las señales de que NO deberías construir una IDP todavía:

NOTE

.5 señales de que NO necesitas (todavía) una IDP

. **< 30 developers**. El coste del platform team es mayor que el ahorro. Usa herramientas standalone.
. **< 50 servicios**. Catalogar manualmente es viable. Automatiza cuando duela.
. **No hay duplicación de trabajo**. Si cada equipo hace su propio deploy de forma distinta y funciona, ¿cuál es el problema a resolver?
. **El equipo está en "feature freeze"**. Las prioridades son de supervivencia, no de productividad.
. **No hay voluntad de invertir 6 meses antes de ver ROI**. La IDP es inversión a medio plazo; si necesitas ROI en 1 mes, no es el momento.
Las excepciones que confirman la regla
humor

"¿Y si tengo 28 developers pero trabajo en un sector regulado donde el compliance es manual y cuesta 100k€/año en auditorías? ¿No vale la pena invertir en una IDP para automatizarlo?". Sí, ese caso es excepción: el ahorro justifica la inversión incluso con pocos developers. Las reglas de "no IDP" son heurísticas, no dogmas.

NOTE

.Excepciones donde SÍ vale la pena incluso con pocos developers

* **Compliance automatizado**: si puedes ahorrar 100k€/año en auditorías, una IDP de 50k€ tiene ROI en 6 meses.
* **Adquisición reciente**: si acabas de absorber otra empresa, una IDP unifica el caos.
* **Crecimiento explosivo**: si pasas de 20 a 100 developers en 1 año, necesitas plataforma ya.
* **Stack muy fragmentado**: 10 lenguajes, 5 bases de datos, 3 clouds. La IDP unifica.
Plan de salida: cómo cerrar una IDP que fracasó

A veces la respuesta correcta es cerrar. No todas las IDPs sobreviven. Si tras 12-18 meses la adopción es < 10%, ROI es negativo, y el equipo está quemado, cerrar es la decisión más profesional.

NOTE

.Plan de salida elegante

. **Comunica la decisión con datos**. "Adopción 7% en 18 meses, ROI -40%, 2 ofertas de renuncia por burnout". El CFO lo entiende.
. **Migra lo que sí funciona** a herramientas standalone (Datadog sigue siendo Datadog).
. **Reconoce al equipo**. "Lo intentamos, aprendimos, no fue un éxito de adopción pero aprendimos qué necesita nuestra organización". Sin culpa.
. **Documenta las lecciones** en un post-mortem público (interno). El próximo intento parte desde aquí.
. **Pausa, no destruyas**. Mantén la infraestructura 6 meses por si hay un giro.
Resumen
  • 9 anti-patrones principales, todos documentados en casos reales.

  • Field of Dreams: construir sin user research.

  • Mandated Adoption: forzar con mandato del CTO.

  • Skill Concentration: senior engineers centralizados.

  • Portal vs Platform: UI bonita sin sistema subyacente.

  • Tool Aggregation: muchas herramientas, ninguna integrada.

  • Big Bang Launch: lanzar todo el día 1.

  • Ticket Queue: platform team como help desk.

  • It works on my machine: sin staging compartido.

  • Infrastructure Project: tratar como proyecto con fecha de fin.

  • A veces NO construir es la decisión correcta.

Glosario del capítulo
Field of Dreams

Construir una plataforma sin user research esperando que los developers la adopten.

Mandated Adoption

Adopción forzada por mandato del CTO en lugar de por valor.

Skill Concentration Trap

Anti-pattern donde todos los senior engineers están en platform team.

Portal vs Platform

Confundir la UI con el sistema subyacente.

Tool Aggregation

Anti-pattern de poner muchas herramientas en un portal sin integración real.

Big Bang Launch

Lanzamiento monolítico después de 12+ meses de desarrollo.

Ticket Queue

Platform team que mide éxito por tickets cerrados.

It works on my machine

Sin staging compartido ni CI/CD obligatorio.

Infrastructure Project

Tratar la plataforma como proyecto con fecha de fin.

Platform as a Product (PaaP)

Mentalidad de tratar la plataforma como producto, con clientes y roadmap.

Cierre del libro

Apéndice A — Git desde cero — si tu equipo nunca ha tocado Git, empieza aquí. Y si llegaste hasta aquí, gracias por leer. La plataforma es solo el medio: lo que importa es liberar tiempo a los developers para que cocinen cosas extraordinarias.

Apéndices

Material de referencia. Lo que se asume como prerrequisito se enseña aquí desde cero. Léelos antes de la Parte 1 si vienes de fuera del mundo backend.

Apéndice A — Git desde cero

Objetivo del apéndice

Darte el mínimo de Git necesario para seguir el libro: clonar, branchear, commitear, pushear y abrir PR.

Instalación
# macOS
brew install git

# Ubuntu/Debian
sudo apt install git -y

# Windows (WSL)
wsl --install
# dentro de WSL: sudo apt install git -y
Configuración inicial
git config --global user.name "Tu nombre"
git config --global user.email "tu@email.com"
git config --global init.defaultBranch main
git config --global pull.rebase true
El flujo mínimo
# Clonar
git clone https://github.com/sazon-foods/backstage-sazon.git
cd backstage-sazon

# Crear rama
git checkout -b feat/sazon-status-plugin

# Editar archivos, luego:
git add .
git commit -m "feat(sazon-status): add /health endpoint"

# Sincronizar y pushear
git pull --rebase
git push origin feat/sazon-status-plugin

# Abrir PR desde la URL que imprime GitHub CLI:
gh pr create --fill
Conceptos clave
  • Working tree: tu carpeta de archivos.

  • Index / Staging: lo que va en el próximo commit (git add).

  • HEAD: el commit actual.

  • Branch: puntero a un commit (rama de trabajo).

  • Remote: el repo en el servidor (origin por convención).

Comandos de rescate
git status                # qué ha cambiado
git diff                  # diff sin stage
git diff --staged         # diff en stage
git log --oneline -10     # últimos 10 commits
git stash                 # guarda cambios sin commitear
git stash pop             # los restaura
git reset --hard HEAD~1   # descarta el último commit (cuidado)
git revert HEAD            # revierte el último commit (seguro)

Apéndice B — Línea de comandos Linux/macOS

Objetivo del apéndice

El mínimo de shell que necesitas para seguir el libro: navegación, ficheros, pipes, procesos y permisos.

Navegación
pwd                       # dónde estoy
ls                        # qué hay aquí
ls -la                    # con ocultos y detalles
cd /ruta                  # cambiar de directorio
cd -                      # volver al directorio anterior
cd ~                      # ir al home
Ficheros
mkdir -p dir/sub          # crear estructura
touch file.txt            # crear/actualizar archivo
cp a.txt b.txt            # copiar
mv a.txt dir/             # mover
rm file.txt               # borrar
rm -rf dir                # borrar recursivo (cuidado)
cat file.txt              # imprimir
less file.txt             # paginar
head -20 file.txt         # primeras 20 líneas
tail -f file.txt          # últimas líneas, sigue creciendo
Pipes y redirección
ls | grep .yaml           # filtrar
cat file | sort | uniq    # encadenar
echo "hola" > file.txt    # sobreescribir
echo "adicional" >> file.txt  # añadir
cmd 2>&1                  # stderr a stdout
cmd > out.log 2>&1        # todo a un archivo
Procesos
ps aux | grep node        # procesos de node
kill PID                  # terminar proceso (SIGTERM)
kill -9 PID               # forzar (SIGKILL)
nohup cmd &               # correr en background, inmune a hangup
jobs                      # trabajos del shell actual
fg %1                     # traer a foreground
Permisos
chmod +x script.sh        # hacer ejecutable
chmod 644 file            # rw-r--r--
chmod 600 key.pem         # rw------- (privado)
chown user:group file     # cambiar dueño
SSH y claves
ssh-keygen -t ed25519 -C "tu@email.com"   # crear clave
ssh-copy-id user@host                     # subir pública
ssh user@host                             # conectar
Atajos del shell
  • :code:`Ctrl+R` — buscar en el historial.

  • :code:`Ctrl+A/E` — inicio/fin de línea.

  • :code:`Ctrl+U/K` — borrar hasta inicio/fin de línea.

  • :code:`!!` — repetir último comando.

  • :code:`sudo !!` — repetir último comando con sudo.

Apéndice C — Docker y Docker Compose

Objetivo del apéndice

Imágenes, contenedores, redes, volúmenes y multi-servicio con Compose. Suficiente para correr Backstage localmente.

Conceptos
  • Imagen: snapshot de un FS + comando de arranque.

  • Contenedor: instancia corriendo de una imagen.

  • Volumen: almacenamiento persistente fuera del FS del contenedor.

  • Red: espacio de nombres donde los contenedores se ven por hostname.

  • Compose: declarativa multi-contenedor en YAML.

Comandos esenciales
docker pull postgres:16           # bajar imagen
docker images                     # listar imágenes
docker run -d --name db postgres:16
docker ps                         # contenedores corriendo
docker ps -a                      # todos
docker logs -f db                 # logs del contenedor
docker exec -it db bash           # shell interactivo
docker stop db                    # parar
docker rm db                      # borrar
docker rmi postgres:16            # borrar imagen
Compose mínimo
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:
docker compose up -d      # arranca en background
docker compose down       # para y borra contenedores (no volúmenes)
docker compose logs -f    # logs agregados
docker compose exec db bash
Dockerfile mínimo (Node)
FROM node:20-bookworm-slim AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build

FROM node:20-bookworm-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 7007
CMD ["node", "dist/index.js"]
Buenas prácticas
  • Imágenes slim (:code:`-slim`) cuando puedas.

  • :code:`HEALTHCHECK` para que Compose sepa si el contenedor está listo.

  • :code:`--init` para que las señales lleguen al proceso principal.

  • Variables de entorno en :code:`.env`, no en el YAML.

Apéndice D — Kubernetes básico

Objetivo del apéndice

Suficiente Kubernetes para desplegar Backstage: Pod, Deployment, Service, Ingress, kubectl. Sin entrar en Operators ni Helm charts avanzados.

Conceptos
  • Pod: 1+ contenedores corriendo juntos en el mismo nodo.

  • Deployment: controladora que mantiene N réplicas de un Pod.

  • Service: punto de acceso estable a un Deployment (ClusterIP, NodePort, LoadBalancer).

  • Ingress: reglas HTTP/S externas (host + path → service).

  • Namespace: aislamiento lógico.

  • ConfigMap / Secret: config y secretos inyectados como env o archivos.

kubectl esencial
kubectl get pods -A
kubectl get svc,ing -A
kubectl describe pod <name>
kubectl logs -f <pod>
kubectl exec -it <pod> -- bash
kubectl apply -f deployment.yaml
kubectl delete -f deployment.yaml
kubectl rollout status deployment/backstage
kubectl rollout undo deployment/backstage    # rollback
kubectl top pod                                # uso de recursos
Deployment mínimo
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backstage
  namespace: backstage
spec:
  replicas: 2
  selector:
    matchLabels: { app: backstage }
  template:
    metadata:
      labels: { app: backstage }
    spec:
      containers:
        - name: backstage
          image: ghcr.io/sazon-foods/backstage:1.31.0
          ports: [{ containerPort: 7007 }]
          envFrom:
            - secretRef: { name: backstage-secrets }
Service e Ingress
apiVersion: v1
kind: Service
metadata: { name: backstage, namespace: backstage }
spec:
  selector: { app: backstage }
  ports: [{ port: 80, targetPort: 7007 }]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: backstage, namespace: backstage }
spec:
  rules:
    - host: backstage.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: backstage
                port: { number: 80 }
Debugging
  • :code:`kubectl describe` > :code:`kubectl get` para problemas (te dice Events).

  • :code:`kubectl logs --previous` para el contenedor que crasheó.

  • :code:`kubectl port-forward svc/backstage 7007:80 -n backstage` para acceso local sin Ingress.

Apéndice E — YAML y JSON

Objetivo del apéndice

YAML suficiente para escribir catalog-info.yaml, app-config.yaml, manifests de K8s y templates del Scaffolder.

Reglas de oro
  • Indentación: 2 espacios (nunca tabs).

  • Claves: :code:`clave: valor` con espacio después de los dos puntos.

  • Listas: :code:`- elemento` (guión + espacio).

  • Strings: comillas solo si hace falta (caracteres especiales, números como string).

  • Comentarios: :code:`# comentario` hasta fin de línea.

Tipos básicos
cadena: "hola"
numero: 42
boolean: true
nulo: null
fecha: 2026-07-23
lista:
  - uno
  - dos
  - tres
mapa:
  clave1: valor1
  clave2: valor2
multilinea: |
  Línea 1
  Línea 2
JSON equivalente
{
  "cadena": "hola",
  "numero": 42,
  "boolean": true,
  "lista": ["uno", "dos"],
  "mapa": { "clave1": "valor1" }
}
Multi-documento (---)
apiVersion: v1
kind: Service
metadata: { name: a }
spec: { selector: { app: a } }
---
apiVersion: v1
kind: Service
metadata: { name: b }
spec: { selector: { app: b } }
Anclas y referencias (& y *)
defaults: &defaults
  retries: 3
  timeout: 30
service-a:
  <<: *defaults
  name: a
service-b:
  <<: *defaults
  name: b
Validador online

Un YAML inválido rompe Backstage al arrancar: valida antes de commitear.

Apéndice F — JavaScript y TypeScript básico

Objetivo del apéndice

Lo mínimo de JS/TS que necesitas para escribir plugins de Backstage. Si vienes de otro lenguaje, este apéndice te da el vocabulario.

Variables y tipos básicos
const name: string = 'sazon';
const port: number = 7007;
const enabled: boolean = true;
const tags: string[] = ['api', 'restaurant'];
const map: Record<string, number> = { a: 1 };
const maybe: string | null = null;
Funciones
function add(a: number, b: number): number { return a + b; }
const greet = (name: string): string => `Hola, ${name}`;
const optional = (x?: number) => x ?? 0;     // nullish coalescing
async function load(): Promise<string> { return 'ok'; }
Objetos e interfaces
interface Service { name: string; port: number; tags?: string[]; }
const svc: Service = { name: 'api', port: 7007 };
const withDefaults: Service = { name: 'api', port: 7007, tags: [] };
Async/Await
async function getStatus(service: string) {
  const res = await fetch(`/api/sazon/status/${service}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json() as Promise<{ status: string }>;
}
Destructuring
const { name, port = 80 } = svc;
const [first, ...rest] = ['a', 'b', 'c']; // first='a', rest=['b','c']
Modules: import/export
import { z } from 'zod';
import type { LoggerService } from '@backstage/backend-plugin-api';

export const StatusSchema = z.object({ service: z.string() });
export type Status = z.infer<typeof StatusSchema>;
Node: package.json mínimo
{
  "name": "@sazon/plugin-x",
  "version": "0.1.0",
  "main": "src/index.ts",
  "scripts": {
    "start": "backstage-cli package start",
    "test": "backstage-cli package test"
  }
}
Tipado estricto

Backstage activa :code:`strict: true` por defecto. Si vienes de JS, prepárate para tipar todo al principio; a la larga, el compilador atrapa errores caros.

Apéndice G — OAuth2/OIDC conceptual

Objetivo del apéndice

OAuth2 y OIDC sin jerga. Lo justo para entender qué pasa cuando haces login en Backstage y qué decisiones tomar como admin.

Roles
  • Resource Owner: el developer (dueño de su identidad).

  • Client: la app que pide datos (Backstage).

  • Authorization Server / IdP: emite tokens (GitHub, Keycloak, Okta).

  • Resource Server: la API que valida el token.

Flujo Authorization Code (el que usa Backstage)
  1. Developer hace clic en "Login with GitHub".

  2. Backstage redirige al IdP.

  3. IdP muestra consentimiento; developer acepta.

  4. IdP redirige a :code:`https://backstage/auth/github/handler?code=XXX`.

  5. Backstage intercambia el code por un access_token (server-to-server).

  6. Backstage pide :code:`/userinfo` con el token.

  7. Backstage crea la sesión (cookie) y devuelve 200.

Tokens
  • Access token: corta duración (minutos). Para llamar a APIs.

  • Refresh token: larga duración. Para renovar el access token.

  • ID token (OIDC): JWT con claims de identidad (sub, email, name).

Claims típicas
{
  "sub": "user:default/tester",
  "email": "tester@sazon-foods.com",
  "preferred_username": "tester",
  "name": "Maite Tester",
  "groups": ["platform-sazon", "engineering"],
  "iss": "https://keycloak.sazon-foods.com/realms/sazon",
  "aud": "backstage",
  "exp": 1720003200
}
Scopes

Definen qué puede pedir el client:

  • :code:`openid` — mínimo OIDC.

  • :code:`profile` — nombre, username.

  • :code:`email` — email.

  • :code:`groups` — grupos (en Keycloak con mapper).

Mejores prácticas
  • Usa Authorization Code with PKCE (no Implicit).

  • Access tokens de corta vida (< 1 h).

  • Refresh tokens en storage seguro del client.

  • Claims de grupos para mapear a Group del catalog.

Apéndice H — Migración de legacy backend (referencia)

Objetivo del apéndice

Cómo pasar del legacy :code:`index.ts` a la New Backend System, con el mapeo uno-a-uno de patrones comunes.

Diferencias clave
Concepto Legacy New Backend System

Punto de entrada

:code:`createPlugin()` + router manual

:code:`createBackendPlugin()` o :code:`createBackendModule()`

Router

:code:`app.use('/api/foo', router)`

:code:`httpRouter.use(await createRouter(…​))`

Config

:code:`Config.getOptionalString(…​)` con lectura directa

:code:`ConfigService` inyectado

Identity

Request headers ad-hoc

:code:`HttpAuthService.credentials()`

DB

:code:`Knex(…​)` instanciado a mano

:code:`DatabaseService` con migraciones

Logging

:code:`winston` o consola

:code:`LoggerService` (pino)

Paso 1 — Reescribir index.ts
// Antes (legacy)
const backend = new Backend({ ... });
backend.add(...);
// muchas líneas de routers
backend.start();

// Después (New Backend System)
const backend = createBackend();
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@sazon/plugin-sazon-status-backend'));
backend.start();
Paso 2 — Convertir plugins
// Antes (legacy)
export default async function createPlugin({ ... }: PluginEnvironment) {
  const router = Router();
  router.get('/foo', ...);
  return router;
}

// Después (New Backend System)
export const fooPlugin = createBackendPlugin({
  id: 'foo',
  register(env) {
    env.registerInit({
      deps: { httpRouter: coreServices.httpRouter },
      async init({ httpRouter }) {
        httpRouter.use(await createRouter({ ... }));
      },
    });
  },
});
Paso 3 — Servicios

Pasa de singletons globales a deps declarativos:

env.registerInit({
  deps: {
    database: coreServices.database,
    logger: coreServices.logger,
    httpAuth: coreServices.httpAuth,
  },
  async init({ database, logger, httpAuth }) { ... },
});
Paso 4 — Custom services

Si tenías un service factory custom, decláralo con :code:`createServiceFactory`:

export const myCustomService = createServiceFactory({
  service: createServiceRef<MyService>({ id: 'my-custom', scope: 'plugin' }),
  factory: async () => MyServiceImpl,
});

Y lo registras con :code:`backend.add(myCustomService)`.

Compatibilidad
  • La legacy backend system sigue operativa en Backstage 1.x.

  • No puedes mezclar: si arrancas con :code:`createBackend(), todos los plugins deben ser NBS o estar envueltos en un :code:`legacyPlugin() shim.

  • Planifica la migración antes de que tu :code:`index.ts` legacy supere 500 líneas.

Apéndice I — Glosario de términos

Objetivo del apéndice

Términos recurrentes del libro, en orden alfabético, con su definición corta y un enlace al capítulo donde se explican.

ApisRegistry

Bus de APIs del shell de Backstage (frontend). Ver :cap-09.

BackendFeature

Unidad que el backend monta: plugin, módulo o service factory. Ver :cap-05.

Bootstrap

Asistente :code:`@backstage/create-app` que genera un monorepo Backstage. Ver :cap-03.

Codemod

Script automatizado que migra código entre versiones de Backstage. Ver :cap-15.

coreServices

Bus de servicios del backend (Database, Cache, Auth, Logger, etc.). Ver :cap-05.

Component

Entidad del catalog que representa un servicio o sitio. Ver :cap-04.

Crossplane

Plataforma K8s que expone recursos cloud como CRDs. Ver :cap-15.

DAU/MAU

Daily/Monthly Active Users. Métrica de adopción. Ver :cap-16.

DiscoveryProcessor

Pieza que descubre entidades desde fuentes externas. Ver :cap-04.

Datasource

Backend que expone datos a la IDP (GitHub, GitLab, AWS). Ver :cap-15.

Entidad

Objeto JSON/YAML del catalog (Component, API, Resource, System, etc.). Ver :cap-04.

EventsService

Bus pub/sub interno del backend de Backstage. Ver :cap-07.

HttpAuthService

Servicio que convierte credenciales HTTP en Principal. Ver :cap-07.

HttpRouterService

Servicio que expone el router HTTP compartido del backend. Ver :cap-05.

IDP

Internal Developer Portal. Portal unificado para developers. Ver :cap-01.

Knex

SQL query builder usado por Backstage. Ver :cap-07.

Kind

Categoría de una entidad del catalog (Component, API, Resource, System, Domain, Group, User). Ver :cap-04.

makeStyles

API de Material UI v4 para crear hooks de estilos tipados. Ver :cap-10.

New Backend System

Arquitectura recomendada desde Backstage 1.20. Ver :cap-05.

OAuth

Protocolo de delegación de autorización. Ver :apéndice G.

OIDC

Capa de identidad sobre OAuth 2.0. Ver :apéndice G.

OpenTofu

Fork open source de Terraform, mantenido por la Linux Foundation. Ver :cap-15.

PermissionPolicy

Función TS que evalúa si una acción está permitida (RBAC). Ver :cap-14.

Principal

Objeto que representa al usuario autenticado (subject, type). Ver :cap-06.

RBAC

Role-Based Access Control. Modelo allow/deny sobre acciones y recursos. Ver :cap-14.

RouteRef

Identificador inmutable de una ruta frontend. Ver :cap-08.

Scaffolder

Plugin de Backstage para generar proyectos desde plantillas. Ver :cap-12.

ServiceMonitor

CRD de Prometheus Operator para descubrir métricas. Ver :cap-15.

signIn.resolver

Función que mapea el usuario autenticado a una entidad User del catalog. Ver :cap-14.

SLO

Service Level Objective. Objetivo medible (latencia, disponibilidad). Ver :cap-15.

System

Entidad que agrupa Components de un mismo dominio. Ver :cap-04.

Tags

Marcadores libres que clasifican entidades. Ver :cap-04.

Template

YAML del Scaffolder que define un flujo generador. Ver :cap-12.

themes.json

Archivo que define paletas light y dark de la IDP. Ver :cap-11.

TTD

Time-to-Dev. Tiempo desde la idea hasta el servicio en producción. Ver :cap-16.

useApi

Hook de Backstage que resuelve un ApiRef en su implementación inyectada. Ver :cap-09.

vendor lock-in

Dependencia técnica que dificulta migrar a otro proveedor. Ver :cap-16.

WCAG

Web Content Accessibility Guidelines. Estándar de accesibilidad web. Ver :cap-10.

Zod

Librería de validación de esquemas para TypeScript. Ver :cap-06.

Apéndice J — Métricas de éxito (resumen ejecutivo)

Objetivo del apéndice

El dashboard que entregas a la CTO al cierre de cada trimestre: 8 KPIs que cuentan si tu IDP está viva o moribunda.

Las 8 métricas que importan
KPI Qué mide Objetivo Cómo medirlo

Catalog coverage

% de servicios registrados

> 80%

:code:`catalogApi.getEntities({ filter: { kind: 'Component' } })` vs fuente de verdad externa

DAU/MAU

Frecuencia de uso

> 60%

Cookies de sesión o logs de acceso autenticado

Template usage

Templates ejecutados / mes

> 5

Contador del scaffolder

TTD medio

Días desde idea a producción

< 3

Scaffolder log + PR open-to-merge time

Owner coverage

Componentes con :code:`spec.owner`

> 95%

Validación del catalog

SLO availability

Uptime mensual

> 99.5%

Prometheus :code:`up{job="backstage"}`

Error rate

% respuestas 5xx

< 1%

Prometheus :code:`rate(http_requests_total{status=~"5.."}[5m])`

Plugin adoption

Plugins con > 1 usuario activo

> 5

Logs de acceso por plugin

Cómo presentar el dashboard
Cada métrica, una respuesta
  • ¿Estamos mejorando? → línea temporal.

  • ¿Dónde estamos hoy? → número + delta vs trimestre anterior.

  • ¿Qué hay que hacer? → acción concreta si la métrica está en rojo.

Un dashboard sin acciones es ruido. Si una métrica está mal, propón un plan para arreglarla en la misma reunión.

Ejemplo de reporte trimestral

Q3 2026 — Backstage Sazón Foods

  • Catalog coverage: 87% (+12 pp vs Q2) — se migraron 14 servicios legacy.

  • DAU/MAU: 64% (+8 pp) — adopción estable en equipos de producto.

  • Templates ejecutados: 23 (12 servicios nuevos, 11 features) — por encima del objetivo.

  • TTD medio: 4.2 días (-2.1 vs Q2) — el scaffolder recortó tiempo de setup.

  • SLO: 99.7% availability (objetivo cumplido).

  • Action item: RBAC queda al 30% de cobertura; objetivo Q4 es 70%.

Verde, amarillo, rojo. Una página. Sin slides.

Por qué importan las métricas
Lo que mides, lo que mejoras
  • Sin métricas, una IDP es "el juguete de platform".

  • Con métricas, es infraestructura: una pieza que falla si no se cuida.

  • Las métricas dan ownership y mejoran la moral del equipo.

El :cap-16 tiene el argumentario para defender estas métricas ante la dirección.