Seguir aprendiendo: leer el código fuente, ver los episodios y un plan de dominio continuo
El track termina aquí, pero el nivel no se alcanza leyendo: se alcanza volviendo. Esta última lección entrega tres instrumentos para que el aprendizaje continúe sin guía. Primero, el orden exacto en que hay que leer el código fuente de TCA para que resulte legible en lugar de abrumador, archivo por archivo y con las técnicas de arqueología que revelan por qué cada decisión está donde está. Después, el mapa de las series de Point-Free y qué pregunta responde cada una. Y por último un plan de práctica deliberada de noventa días, con el criterio para mantenerse al día sin perseguir cada versión que sale.
Hay una asimetría incómoda al terminar un track largo: sabes más de lo que puedes demostrar y menos de lo que crees. La única cura conocida es dejar de consumir material y empezar a re-derivar, y para eso hacen falta tres cosas que esta lección entrega en orden. La primera es aprender a leer código de bibliotecas, que es la habilidad de mayor rendimiento de toda la profesión y la que menos se enseña: TCA cabe en una tarde de lectura si se abre por los archivos correctos, y en un mes de frustración si se abre por el índice. La segunda es saber qué material existe y qué pregunta responde cada pieza, para no ver ocho horas de vídeo buscando algo que estaba en un artículo. Y la tercera es un plan, porque el dominio no llega por acumulación sino por repetición dirigida sobre las partes que todavía no puedes reconstruir de memoria.
- Leer el código fuente de TCA en un orden que lo haga legible, y usar el historial de
gitcomo documentación. - Situar las series de Point-Free y saber cuál responde a la duda que tienes ahora mismo.
- Ejecutar un plan de práctica deliberada de noventa días con entregables verificables.
- Evaluar versiones y novedades por el tipo de bug que eliminan, no por su novedad.
Leer el código fuente en el orden correcto
TCA es una biblioteca legible, pero solo si se entra por donde debe. El error universal es abrir Store.swift o TestStore.swift, que son los archivos más grandes y los que suponen conocido todo lo demás. El orden que funciona va de la abstracción a su implementación y de ahí al runtime, y en los primeros cuatro archivos ya está la tesis completa; lo demás es ingeniería para que la tesis sobreviva al mundo real.
git clone https://github.com/pointfreeco/swift-composable-architecture
cd swift-composable-architecture/Sources/ComposableArchitecture
# El orden de lectura, de menos a mas presupuesto de contexto
wc -l Reducer.swift Reduce.swift Effect.swift Scope.swift Store.swift TestStore.swift
| Paso | Archivo o carpeta | Qué vas a entender ahí |
|---|---|---|
| 1 | Reducer.swift |
El protocolo entero: State, Action, reduce y body. La tesis en cien líneas |
| 2 | Reduce.swift |
Que el caso base es trivial, y por qué eso cierra la abstracción |
| 3 | Effect.swift |
Que Effect es un enum con muy pocos casos, no una cosa mágica |
| 4 | Scope.swift |
Toda la composición: dos proyecciones y una llamada al hijo |
| 5 | ReducerBuilder.swift |
Cómo el body acepta varios reducers sin operadores explícitos |
| 6 | Store.swift |
El runtime: el ciclo, el aislamiento y la observación de la vista |
| 7 | Observation/ |
Cómo se conecta con Observation y qué hace la macro de estado |
| 8 | TestStore.swift |
El último, y solo con los siete anteriores leídos |
La segunda mitad de la habilidad no es leer el código sino leer su historia. Cuando un fragmento parezca arbitrario —una comprobación extraña, un @inlinable inesperado, una copia defensiva— la pregunta útil no es qué hace sino qué incidente provocó esto, y esa pregunta tiene respuesta mecánica en el repositorio.
# Quien introdujo esta linea y en que commit, con el mensaje completo
git log -L 40,60:Store.swift
# Cuando aparecio y cuando desaparecio una idea concreta en toda la historia
git log -S "cancellable" --oneline -- Sources/
# La documentacion oficial vive en el propio repositorio, no solo en la web
ls Sources/ComposableArchitecture/Documentation.docc/Articles
Queda una tercera técnica, y es la que disuelve la sensación de magia que dejan las macros. El código que @Reducer y @ObservableState escriben por ti es Swift corriente y se puede ver: en el editor, desplegando la expansión desde el menú contextual de la macro; en la línea de comandos, pidiéndole al compilador que la vuelque. Media hora leyendo esa expansión retira para siempre la idea de que ahí ocurre algo que no podrías haber escrito a mano.
# Volcar lo que las macros generan, para leerlo como codigo normal
swift build -Xswiftc -dump-macro-expansions
Entra por el protocolo
Reducer.swift antes que Store.swift. La abstracción primero, el runtime después, nunca al revés.
Pregunta al historial
Toda línea rara tiene un commit que la explica. git log -S convierte el repositorio en documentación.
Expande la macro
Lo que genera @Reducer es texto legible. Verlo una vez elimina toda la magia percibida.
Lee la docc del repo
Los artículos y las guías de migración viven junto al código y explican el porqué, no solo el cómo.
En este repositorio, casi todo archivo tiene su gemelo en Tests/, y el gemelo es más legible que el original porque enuncia el comportamiento sin las defensas. Si PresentationReducer te resulta opaco, abre su prueba: verás una feature mínima, un estado que se anula y la afirmación exacta de qué efectos se cancelan. Diez minutos de pruebas ahorran una hora de implementación, y de paso te enseñan a escribir las tuyas, porque son las de la gente que diseñó la API.
El material de Point-Free y qué pregunta responde
El catálogo es enorme y desordenado si se aborda cronológicamente, porque abarca años y varias reescrituras de la propia biblioteca. Ordenado por pregunta, en cambio, es sorprendentemente compacto. La regla práctica es no empezar por la serie de la arquitectura: casi todo lo que hace única a TCA se explica mejor en las series que la preceden, donde las ideas aparecen aisladas y sin el peso del framework.
| Serie | Pregunta que responde | Cuándo verla |
|---|---|---|
| Tipos de datos algebraicos | Por qué modelar con enum y struct elimina estados imposibles |
Antes que nada, aunque uses otra arquitectura |
| Case paths | Por qué los enums merecían la ergonomía de las structs | Cuando escribas tu tercer ifCaseLet |
| Testigos de protocolo | Por qué un struct de closures sustituye a un protocolo |
Antes de diseñar tus dependencias |
| Dependencias | Cómo se controla el mundo sin inyectarlo a mano | Cuando tengas un test intermitente |
| Tour de la arquitectura | La visión completa con código real y en abierto | Para repasar el track de una sentada |
| SwiftUI moderno | Cómo se escribe una app sin TCA con sus mismas ideas | Antes de proponerla en un equipo escéptico |
| Navegación componible | Por qué la navegación es un valor y qué cuesta modelarla | Cuando la pila se te resista |
| Estado compartido | Qué problema resuelve @Shared y cuál no |
Al segundo singleton que quieras retirar |
Conviene además saber cómo se consume ese material sin perder la tarde. Buena parte del catálogo es de pago, pero hay episodios abiertos en cada serie y, sobre todo, cada episodio publica su transcripción completa y el proyecto de código de cada paso; para una duda concreta, buscar en la transcripción y abrir el proyecto es diez veces más rápido que ver el vídeo entero. La disciplina que mejor funciona es no ver nada sin una pregunta escrita de antemano y cerrar el episodio en cuanto esa pregunta tenga respuesta.
Al material en vídeo hay que añadirle dos fuentes que se consultan más y se citan menos. La primera son las guías de migración en la documentación del repositorio, que son la única explicación honesta de por qué una API se sustituyó por otra y qué se aprendió en el intento. La segunda son las apps de ejemplo, con SyncUps como pieza central —una reconstrucción completa de una app de Apple— y con el juego isowords como muestra de una base de código real, grande y publicada entera, incluido su servidor.
flowchart LR L[Leer fuente] --> C[Construir algo pequeno] C --> R[Re-derivar sin mirar] R --> E[Ensenar o escribir] E --> D[Detectar el hueco] D --> L D --> P[Contribuir o preguntar] P --> L style L fill:#89b4fa,color:#11111b style R fill:#fab387,color:#11111b style E fill:#a6e3a1,color:#11111b
Noventa días de práctica deliberada
Un plan sirve si tiene entregables comprobables y si cada semana ataca algo que todavía no puedes hacer sin ayuda. El que sigue está diseñado con esa regla y con una segunda, más dura: nada cuenta si se hizo mirando la solución. Reconstruir con el modelo delante es leer; reconstruir sin él es aprender, aunque tarde el triple.
// Semana 4, entregable: escribe esto de memoria antes de abrir la documentacion
@Reducer struct Feature {
@ObservableState struct State: Equatable { }
enum Action { }
var body: some ReducerOf<Self> { Reduce { state, action in .none } }
}
// Si dudaste en la firma de body o en el retorno del Reduce, ahi esta tu hueco
| Semanas | Actividad | Entregable comprobable |
|---|---|---|
| 1 y 2 | Leer el fuente en el orden de la tabla | Un cuaderno con diez dudas y su respuesta hallada en el historial |
| 3 y 4 | Reconstruir SyncUps sin abrir el original |
Tu árbol de estado y una nota por cada diferencia con el suyo |
| 5 a 8 | Portar una pantalla real de tu trabajo | Su módulo, sus dependencias y sus pruebas de nodo y de arista |
| 9 a 12 | Salir del consumo | Una duda ajena respondida y una contribución aceptada |
La última fila es la que casi todo el mundo salta y la que más rinde. Responder la duda de otra persona te obliga a construir un ejemplo mínimo, a comprobar que compila y a estar en lo cierto delante de alguien que puede contradecirte; es práctica deliberada disfrazada de amabilidad. Y la contribución más fácil de que te acepten no es una función nueva sino una corrección de documentación, que exige entender exactamente igual de bien y no arriesga nada del diseño ajeno.
Ver vídeos, leer artículos y coleccionar plantillas produce una sensación de progreso que no se corresponde con ninguna capacidad nueva, porque el reconocimiento es mucho más fácil que la reconstrucción. La prueba honesta es siempre la misma: cierra todo y escribe la pieza de memoria. Si no sale, no la sabías; sabías reconocerla. Aplica esa prueba a las tres cosas que más se dan por sabidas —la firma del reducer, cómo se cancela un efecto y qué falla exactamente un TestStore— y verás que la lista de huecos reales es corta y muy distinta de la que imaginabas.
Mantenerse al día sin perseguir versiones
La biblioteca se mueve, y con ella todo el ecosistema. La estrategia sostenible no es actualizar por deporte sino tener un criterio para decidir. Ante una novedad, la pregunta útil no es si es elegante sino qué categoría de error elimina: si la respuesta es ninguna, pero se escribe más corto, puede esperar sin coste; si la respuesta es hace imposible un estado que hoy puedo construir, entonces conviene adoptarla pronto, porque su valor crece con cada línea que escribas sin ella.
# Que subiria y hasta donde, sin tocar todavia el lockfile
swift package update --dry-run
# Cada version mayor trae su guia de migracion dentro del propio repositorio
ls Sources/ComposableArchitecture/Documentation.docc/Migration*
Las deprecaciones de esta biblioteca vienen casi siempre con el reemplazo indicado en el propio aviso, de modo que la mayoría de las migraciones se resuelven aplicando las correcciones automáticas del editor y leyendo el artículo correspondiente para los tres casos que no se pueden automatizar. Silenciar esos avisos es la decisión que convierte una tarde de trabajo en una semana, porque el aviso desaparece pero la API antigua sigue caducando igual.
Hay además un sitio donde preguntar y un modo de hacerlo. Las discusiones del repositorio son el canal principal y están muy bien atendidas por los propios autores, con una condición implícita que conviene respetar: una pregunta acompañada de un caso reducido —una feature de treinta líneas y un test que falla— recibe respuesta casi siempre, y una pregunta descrita en prosa sobre un proyecto que nadie puede ejecutar casi nunca. Reducir el caso es, de hecho, el ejercicio que más veces resuelve la duda antes de llegar a publicarla.
El resto es higiene conocida: fijar versiones en el manifiesto, actualizar en una rama propia y con las pruebas verdes antes de tocar nada, leer las notas de versión completas en lugar del titular, y tratar cada aviso de deprecación como trabajo pendiente y no como ruido. Un proyecto que hace esto se mantiene indefinidamente al día con un esfuerzo pequeño y constante; uno que lo pospone acumula una migración de tres versiones que nadie quiere empezar y que acaba justificando, años después, la decisión de no volver a usar bibliotecas externas.
Termina aquí un recorrido de treinta y un niveles y conviene ser explícito sobre qué debería haber cambiado, porque no es lo que suele suponerse. No has terminado sabiendo TCA de memoria, y no deberías: la memoria es el peor sitio donde guardar una API que cambiará. Lo que debería haber cambiado es tu capacidad de re-derivación. Si mañana olvidaras la firma exacta de ifLet, deberías poder reconstruirla razonando: el hijo vive en un opcional, luego el operador necesita un key path a ese opcional, un case path a la acción del hijo y el reducer hijo; y como el hijo puede desaparecer, alguien tiene que cancelar sus efectos al anularse, luego el operador debe hacerlo por ti. Eso no es recordar, es deducir desde el invariante, y es la única forma de conocimiento que sobrevive a las versiones. Por eso el criterio de que has alcanzado el nivel no es aprobar un examen de API sino algo más incómodo de fingir: poder abrir un archivo del fuente que nunca has leído y predecir aproximadamente qué vas a encontrar antes de leerlo. Hay una segunda cosa que debería haber cambiado, más silenciosa y probablemente más valiosa a largo plazo, y es tu relación con el código ajeno. Antes de este track, una biblioteca era una caja negra con una documentación; después, es un texto escrito por gente que se enfrentó a los mismos problemas que tú, dejó su razonamiento en el historial y expuso sus dudas en las pruebas. Leer bibliotecas se convierte, con la práctica, en la fuente de aprendizaje más rápida disponible, porque es la única donde ves decisiones reales con sus consecuencias reales en lugar de ejemplos diseñados para funcionar. Y hay un último cambio, el que de verdad justifica haber recorrido treinta y un niveles: la disposición a pagar el precio de nombrar las cosas. Casi todos los problemas difíciles de esta profesión son, en el fondo, algo que nadie quiso nombrar y que por eso quedó implícito —un estado que no está en ninguna estructura, un evento que no está en ningún tipo, una dependencia que no está en ninguna firma— y todos los sistemas que envejecen mal envejecen así. Si al terminar este track tu reflejo ante un problema confuso es preguntar qué no está nombrado aquí, entonces el track ya no hace falta y su trabajo está hecho, con TCA o sin ella, en Swift o en lo que venga después.
- Clona el repositorio y lee los cuatro primeros archivos de la tabla en una sola sesión. Anota tres decisiones que no entiendas y resuelve cada una con
git log -So con la prueba correspondiente. - Cierra todo y escribe de memoria una feature completa con estado, acción, dependencia, efecto cancelable y su prueba. Cronometra y guarda el resultado como línea base.
- Reconstruye
SyncUpssin mirar el original. Al terminar, compara ambos árboles de estado y escribe por qué difieren; cada diferencia es una decisión de diseño que ahora puedes justificar o corregir. - Elige una novedad reciente del ecosistema y decide si adoptarla aplicando el criterio del bug eliminado. Escribe la decisión en dos frases y la fecha, para poder revisarla dentro de seis meses.
- Haz una contribución pública, por pequeña que sea: una duda respondida, una incidencia reducida a veinte líneas o una corrección de documentación. Es el único ejercicio de esta lista que te obliga a estar en lo cierto ante alguien más.