wandres.dev
TCA VS ALTERNATIVAS · el juicio honesto

El veredicto matizado: dónde gana TCA y cómo decidirlo con datos

El cierre del nivel convierte cuatro lecciones de comparación en un procedimiento ejecutable. Enumera con precisión los cinco perfiles de producto y equipo donde TCA gana de forma clara y los cinco donde pierde, nombra sin eufemismos los motivos irracionales por los que se adopta igual, y propone después un ensayo doble medible: la misma pantalla escrita dos veces con criterios de aceptación idénticos, seis métricas con pesos declarados de antemano y una regla de decisión escrita antes de ver los resultados. Termina con lo único que hace tolerable equivocarse: cómo mantener la decisión reversible durante los años en que va a estar viva.

⏱ 24 min

Después de comparar TCA con MVVM, con sus ancestros de la web, con su propia factura y con la lista de casos donde no toca, queda la parte que casi nunca se escribe: cómo se decide. No con una recomendación general, que sería exactamente el tipo de consejo que este nivel entero ha intentado desmontar, sino con un procedimiento que produzca una respuesta defendible para tu producto, tu equipo y tu momento. Lo que sigue es un veredicto con condiciones explícitas y, después, un protocolo experimental barato que puede ejecutarse en una semana y que sustituye la discusión de sobremesa por seis números y una regla escrita antes de conocerlos.

🎯 Al terminar esta lección sabrás
  • Enunciar los perfiles de producto y equipo donde TCA gana de forma clara, y los simétricos donde pierde.
  • Nombrar los motivos no técnicos que empujan la adopción, para poder descontarlos de la decisión.
  • Ejecutar un ensayo doble con métricas y pesos declarados antes de ver los resultados.
  • Mantener la decisión reversible durante toda la vida del código, decidas lo que decidas.

Dónde gana claramente

Hay cinco condiciones y la fuerza del argumento crece con cuántas se cumplen a la vez, no con cuál. La primera es la longevidad: código que va a vivir años y que será modificado por gente que no lo escribió. La segunda es el tamaño del equipo, porque a partir de tres o cuatro personas la uniformidad vale más que la velocidad individual y una arquitectura impuesta por el compilador deja de ser una preferencia para convertirse en infraestructura de coordinación.

La tercera es el coste de un fallo de estado. Hay dominios donde un estado corrupto significa un píxel mal puesto y otros donde significa un cobro duplicado, un mensaje enviado a la persona equivocada, una dosis registrada dos veces o una operación irreversible. Cuando la respuesta a la pregunta de cuánto cuesta que esto ocurra una vez es incómoda, todo el argumento cambia de signo. La cuarta es la densidad de asincronía: sincronización sin conexión, tiempo real, varias fuentes que se contradicen, reintentos, conflictos. Ese es el terreno donde MVVM se degrada más rápido y donde la ventaja es mayor.

Y la quinta es la exigencia de demostrar cosas, que suena abstracta hasta que se ve escrita. Cuando un requisito dice que una operación no puede ocurrir dos veces, la diferencia entre las arquitecturas es si esa frase es una intención documentada o una afirmación ejecutable que se rompe en integración continua el día que alguien la viole.

@Test func confirmarDosVeces_noProduceUnSegundoCobro() async {
  let store = TestStore(initialState: Pago.State(enCurso: true)) { Pago() }
  await store.send(.confirmarPulsado)  // no cambia el estado y no devuelve efecto
  await store.finish()                 // y no queda ningun efecto vivo al terminar
}

Ese test no comprueba un comportamiento: comprueba una imposibilidad, y lo hace sin simulador, sin red y en milisegundos. Auditorías, requisitos regulatorios y la simple necesidad de reproducir un informe de fallo exactamente se apoyan en la misma propiedad, que la navegación como dato y el estado serializable llevan hasta el final.

Dónde pierde, y por qué se elige igual

Los simétricos ya se enumeraron en la lección anterior y no hace falta repetirlos: vida corta, poca superficie, persona única, dominio cuya dificultad está en otra parte, y ausencia de apetito. Merece más atención el fenómeno incómodo de por qué se adopta igual en esos casos.

Conviene decirlo sin adornos porque reconocerlo es la única forma de descontarlo. Se adopta por currículum, porque figurar en el proyecto que la usa mejora la siguiente entrevista. Se adopta por identidad de equipo, porque la ceremonia produce una sensación de rigor que resulta agradable con independencia de que esté comprando algo. Se adopta por autoridad, porque quienes la promueven son buenos y explican bien, que es un argumento sobre ellos y no sobre tu proyecto. Y se adopta por miedo, tras un incidente concreto, generalizando de un fallo a una reestructuración completa.

La simetría es igual de real y se menciona menos: también se rechaza por motivos que no son técnicos. Se rechaza porque la primera hora de contacto fue frustrante y nadie vuelve a intentarlo, porque quien la propuso cae mal, porque el equipo asocia estructura con burocracia, o simplemente porque el coste está escrito y el beneficio no. Ninguno de esos motivos, en ninguna de las dos direcciones, es ilegítimo como emoción; todos lo son como criterio, y todos se neutralizan con el mismo gesto: escribir la regla de decisión antes de mirar los datos.

💡
Escribe la regla antes de ver los números

El sesgo más peligroso de cualquier evaluación técnica es elegir el criterio después de conocer el resultado. Antes de empezar el ensayo, escribe en un documento qué métricas vas a mirar, qué peso tiene cada una y qué resultado concreto te haría cambiar de opinión. Si no eres capaz de nombrar un resultado que te haría rechazar la opción que prefieres, no estás evaluando: estás justificando.

Decidir con datos: el ensayo doble

El experimento es sencillo, cuesta una semana de dos personas y produce información que ninguna lectura sustituye. Se elige la segunda pantalla más difícil de la app —no la más difícil, que suele ser atípica, ni un contador, que es un juguete— y se implementa dos veces con los mismos criterios de aceptación, la misma calidad exigida y las mismas costuras inyectadas en ambas versiones.

Después se miden seis cosas. Las tres primeras son de construcción y son las que todo el mundo mide: líneas separando lógica de nomenclatura, tiempo hasta la primera versión que funciona, y tiempo de compilación incremental tras editar el cuerpo. Las tres siguientes son las que de verdad deciden, y casi nadie las mide.

La cuarta es el tiempo hasta completar un cambio especificado de antemano y guardado sin mirar. Se redacta antes de escribir una sola línea, precisamente para que ninguna de las dos versiones se diseñe sabiendo qué le van a pedir después, que es el sesgo que arruina la mayoría de estos ensayos.

// Sobre cerrado: identico criterio de aceptacion para las dos versiones
// 1. El pedido gana un cupon que altera el total y la validacion
// 2. El cupon se valida contra un servicio remoto que puede fallar o tardar
// 3. Mientras se valida, confirmar queda deshabilitado y no admite dos pulsaciones
// 4. Si el servicio falla, el pedido queda utilizable y el error es visible

La quinta métrica es cuántos casos pudiste testear de verdad y cuánto tarda esa suite, contando solo los tests que se escribieron sin heroicidades. Y la sexta es la fricción subjetiva de cada persona en una escala corta, que no es un dato blando sino el mejor predictor disponible de si la disciplina seguirá viva dentro de un año.

⚠️
El sesgo de autoría arruina el ensayo si no lo controlas

Si la versión con TCA la escribe quien ya la conoce y defiende, y la otra quien no, no has medido arquitecturas sino familiaridad. Haz que cada persona escriba una versión de cada tipo, o intercambia los papeles a mitad de semana, y sepáralo del cronómetro: el tiempo del cambio sellado debe medirse cuando ambas versiones ya existen y ambas personas conocen las dos.

Métrica Peso sugerido Qué predice
Tiempo del cambio sellado alto el coste dominante durante toda la vida del código
Cobertura real y tiempo de suite alto cuántos fallos se detectan antes de producción
Fricción subjetiva del equipo alto si la arquitectura seguirá viva dentro de un año
Compilación incremental medio la calidad del bucle diario
Tiempo hasta la primera versión bajo se paga una vez y engaña siempre
Líneas totales muy bajo correlaciona mal con todo lo demás

El orden de esa tabla es la mitad del contenido de la lección. La métrica que la industria cita más —líneas— es la que menos predice, y la que casi nadie mide —tiempo hasta completar un cambio no anticipado— es la que gobierna el presupuesto de los próximos años, porque escribir código por primera vez es una fracción pequeña de lo que se hace con él.

Mantener la decisión reversible

Decidas lo que decidas, vas a acertar con una probabilidad razonable y no mucho más, así que la habilidad que más rinde no es elegir bien sino abaratar el error. Cuatro prácticas lo consiguen y todas mejoran el código aunque nunca cambies de idea.

La primera es mantener el dominio en Swift plano: reglas de negocio, cálculos, validaciones y tipos sin ninguna importación de la arquitectura. Si algún día migras, esa capa se queda intacta, y mientras tanto es la parte más fácil de testear que tendrás. La segunda es la frontera de módulo por feature, que permite convivir dos arquitecturas sin que se contaminen y hace posible migrar una pantalla sin tocar las demás. La tercera es una capa de vista delgada, sin lógica, para que el cambio de arquitectura no arrastre la interfaz. Y la cuarta es adoptar por pantallas y no por proyecto, empezando por la que cumple más condiciones de la primera sección.

Conviene además escribir el plan de retirada el mismo día que se adopta, mientras la decisión todavía no tiene defensores emocionales. Basta con tres frases: qué pantalla sería la primera en volver atrás, qué señal concreta dispararía esa vuelta —por ejemplo que la fricción subjetiva siga alta a los seis meses, o que el bucle de compilación no baje del umbral acordado— y quién tiene la autoridad para decidirlo sin necesidad de una reunión. Un plan de retirada escrito no aumenta la probabilidad de retirarse; la baja, porque convierte la adopción en un experimento con criterios en vez de en una posición que hay que defender.

// El dominio no sabe que existe ninguna arquitectura
struct Pedido: Equatable {
  var lineas: [Linea]
  var total: Decimal { lineas.reduce(0) { $0 + $1.subtotal } }
  func validar() -> [ErrorDePedido] { ... }
}

// El reducer solo orquesta llamadas a codigo que sobrevive a cualquier migracion
case .confirmarPulsado:
  let errores = state.pedido.validar()
  guard errores.isEmpty else { state.errores = errores; return .none }
  return .run { [pedido = state.pedido] send in
    await send(.respuesta(Result { try await api.enviar(pedido) }))
  }
🏛️

Gana con longevidad

Años de vida, varias manos y un dominio donde un estado corrupto cuesta dinero o confianza.

🎭

Descuenta los motivos ajenos

Currículum, identidad, autoridad y miedo empujan la decisión. Nómbralos para poder restarlos.

✉️

El cambio sellado

Especifica la modificación antes de escribir nada. Es la única métrica que mide lo que de verdad harás.

↩️

Abarata el error

Dominio en Swift plano, fronteras por módulo y vistas delgadas. Migrar deja de ser una reescritura.

flowchart TD
I[Escribe la regla de decision] --> E[Implementa la misma pantalla dos veces]
E --> M1[Mide construccion]
E --> M2[Mide el cambio sellado]
E --> M3[Mide cobertura y friccion]
M1 --> P[Puntua con los pesos declarados]
M2 --> P
M3 --> P
P --> D[Decide por modulo y no por proyecto]
D --> R[Manten dominio y fronteras reversibles]
style M2 fill:#89b4fa,color:#11111b
style R fill:#a6e3a1,color:#11111b
La arquitectura correcta no la determina su calidad sino la distribución de los cambios que vas a recibir, y esa distribución ya está escrita en tu repositorio

Después de cuatro lecciones de comparación, la conclusión que queda es incómoda para quien esperaba un veredicto: la calidad intrínseca de una arquitectura explica una parte sorprendentemente pequeña de si funcionará en un proyecto concreto. Lo que lo explica casi todo es la forma de la distribución de cambios que ese código va a recibir a lo largo de su vida, y esa distribución no es una incógnita metafísica sino un dato empírico que ya está registrado en el historial de tu repositorio, esperando a que alguien lo mire. Cada arquitectura es un compromiso entre el coste de escribir por primera vez y el coste de modificar sin contexto; TCA desplaza ese compromiso agresivamente hacia lo segundo, encareciendo el primer día para abaratar los mil siguientes. Si tu distribución tiene mucha masa en la cola larga —código tocado durante años por manos que rotan— ese desplazamiento es exactamente lo que necesitas, y la ceremonia deja de parecer un impuesto para revelarse como lo que es, una forma de trasladar conocimiento del cerebro de las personas al sistema de tipos, donde no se olvida y no se va de la empresa. Si tu distribución está concentrada en las primeras semanas, el mismo desplazamiento es una pérdida limpia. Y como la mayoría de las apps reales contienen las dos distribuciones a la vez, en módulos distintos, la respuesta madura casi nunca es única para todo el proyecto. Hay una segunda lectura, más general, que este nivel entero ha estado preparando: la habilidad profesional que aquí se ejercita no es saber TCA, que es un conocimiento con fecha de caducidad y que otra librería sustituirá, sino saber leer un sistema y decir dónde está su riesgo, qué garantías compensan pagarse y cuáles sobran. Esa habilidad se traslada intacta a MVVM, a Compose, a la web y a lo que venga después, y sobrevive a todas las librerías que la enseñaron. Quien la tiene puede adoptar TCA con convicción o rechazarla con argumentos, y en ambos casos defender su decisión con números; quien no la tiene solo puede repetir la conclusión de otro, que es lo mismo que no haber decidido.

⚔️ Ejecuta el ensayo y firma tu decisión
  1. Redacta la regla de decisión completa: métricas, pesos y el resultado concreto que te haría rechazar la opción que hoy prefieres. Fecha el documento antes de escribir código.
  2. Elige la segunda pantalla más difícil de tu app e implementa las dos versiones con criterios de aceptación idénticos y las mismas costuras inyectadas en ambas.
  3. Especifica el cambio sellado antes de empezar, guárdalo sin mirarlo y aplícalo al final a las dos versiones cronometrando por separado.
  4. Puntúa con los pesos que escribiste, no con los que te gustarían después. Anota también la fricción subjetiva de cada persona en una frase suya, textual.
  5. Escribe el veredicto por módulos, no por proyecto, y añade el plan de reversibilidad: qué dominio queda en Swift plano, qué fronteras separan las features y qué pantalla sería la primera en volver atrás si te equivocaste.