Saltar al contenido

Ser experto: depuración, core y dominio continuo

La maestría en Solid no es conocer la API sino diagnosticar el grafo: distinguir los dos modos de fallo reactivo —no actualiza porque perdiste el tracking, o actualiza de más por sobre-suscripción— y saber inspeccionar sources, observers y ownership para localizar la causa. Esta lección culminante cubre la depuración reactiva avanzada con las Devtools y las técnicas de aislamiento, cómo leer y contribuir al core de Solid y a solid-primitives, y un plan de dominio continuo que sostiene la experticia mucho después de terminar el track y hacia Solid 2.0.

Depuración reactiva avanzada

Casi todo bug reactivo cae en uno de dos cubos, y nombrarlo es medio arreglo. El primero es «no actualiza»: cambiaste un valor y la UI no reaccionó. La causa es siempre la misma familia —perdiste el tracking—: destructuraste props y leíste el valor una vez muerto el listener; leíste un signal fuera de un scope reactivo, en el cuerpo del componente en vez de dentro del JSX o de un efecto; o guardaste algo en una variable plana creyendo que era reactivo.

El segundo es «actualiza de más»: algo recomputa o repinta cuando no debía. La causa es la simétrica —tienes una arista que sobra—: falta un createMemo que corte la propagación, un equals mal configurado que notifica ante valores iguales, o un efecto que escribe un signal que él mismo lee y se realimenta en bucle. La belleza del diagnóstico es que estos dos cubos son exhaustivos: un grafo de sources y observers no tiene una tercera forma de romperse.

La herramienta principal es Solid Devtools, que dibuja el grafo y el árbol de ownership y te deja ver, literalmente, qué observa qué: un source con más observers de los que esperabas es un diagnóstico de «actualiza de más» hecho imagen.

Las técnicas complementarias son de bisección. Aísla una lectura sospechosa con untrack para confirmar si esa arista era el problema; fuerza dependencias explícitas con on para ver exactamente de qué depende un efecto; nombra tus computaciones y añade console.log dentro para observar cuándo corren. Y cuando la duda es profunda, mira el output compilado: como el compilador decide qué es reactivo, leer en qué convirtió tu JSX resuelve de raíz los misterios de «por qué esto no rastrea».

El fallo más común de «no actualiza» es también el más instructivo, porque su arreglo revela el mecanismo. Al destructurar props lees el valor una vez, muerto el listener, y la arista nunca se crea; la cura es conservar la lectura como acceso a props, que es un proxy reactivo.

TSX
// NO ACTUALIZA: destructurar lee el valor una vez y pierde la aristafunction Saludo({ nombre }: Props) { return <h1>Hola {nombre}</h1>; } // roto// ARREGLADO: acceder por props mantiene la lectura dentro del scope reactivofunction Saludo(props: Props) { return <h1>Hola {props.nombre}</h1>; } // vivo

Y el fallo de «actualiza de más» se aísla con on y untrack: declaras la dependencia real y lees el resto sin suscribirte, de modo que solo lo que debe disparar el efecto lo dispara.

TSX
// aislar la causa: si al envolver en untrack el sintoma cambia,// esa lectura era la arista culpablecreateEffect(on(  () => props.id,                 // dependencia EXPLICITA: solo id lo dispara  (id) => {    const extra = untrack(() => props.datos); // leido sin suscribir    cargar(id, extra);  }));

La disciplina que unifica todo esto es negarse a adivinar. Ante un síntoma reactivo, el principiante cambia cosas hasta que «funciona» y no sabe por qué; el experto formula una hipótesis —«esta arista sobra», «esta arista falta»—, la aísla con una herramienta, y confirma o descarta. Depurar deja de ser prueba y error y se vuelve ciencia: observación, hipótesis, experimento controlado. Esa transición mental, de tantear a razonar sobre el grafo, es exactamente el umbral de la experticia.

Leer y contribuir al core

Llega un punto en que la documentación no basta y la respuesta está en la fuente. El ecosistema de Solid es un monorepo de piezas legibles: solid-js con el núcleo reactivo, dom-expressions con el compilador, solid-router y solid-start con el meta-framework, y seroval con la serialización que hace posible el SSR.

El orden de lectura importa, y hay uno óptimo. Empieza por el archivo de signals de solid-js, que define createSignal, createEffect y createMemo sobre la misma mecánica de sources, observers y el listener actual que ya entiendes; sigue por el módulo de ownership, donde viven createRoot, getOwner y la disposición; y solo entonces baja a dom-expressions para ver cómo el compilador teje ambos. Leído en ese orden, el core no es un salto al vacío: es reconocer en TypeScript, capa por capa, lo que este track te explicó en prosa.

Para comprobar que lo entiendes, el núcleo reactivo cabe en un puñado de líneas. Un signal es una lista de observers y un valor; leerlo registra al listener actual, escribirlo notifica a todos. Reconocer este esqueleto en el código real del core deja de ser intimidante cuando lo has escrito tú.

TypeScript
// La esencia del core, sin azucar: la maquina que este track te explicolet listenerActual: (() => void) | null = null;function signal<T>(valor: T) {  const observers = new Set<() => void>();  const leer = () => {    if (listenerActual) observers.add(listenerActual); // arista de grafo al leer    return valor;  };  const escribir = (v: T) => {    valor = v;    for (const obs of [...observers]) obs();            // notifica al cambiar  };  return [leer, escribir] as const;}function efecto(fn: () => void) {  const correr = () => { listenerActual = correr; fn(); listenerActual = null; };  correr(); // al correr, cada signal leido lo registra: tracking automatico}

Contribuir no exige reescribir ese runtime. El camino real empieza por lo pequeño: una reproducción mínima de un bug en un issue vale oro y es una contribución de pleno derecho; una mejora de documentación aclara el punto en que tú tropezaste; un primitivo en solid-primitives, la colección oficial, aplica el patrón del cuarteto que ya dominas y pasa por revisión de los mantenedores.

Desde ahí se sube hacia el diseño en vivo, que ocurre en el Discord y en las discusiones de RFC. Y el momento para entrar es ahora, porque Solid 2.0 está reescribiendo el núcleo reactivo hacia una reactividad asíncrona transparente: el async/await deja de ser un ciudadano aparte y se integra en el grafo, de modo que un memo puede esperar sin romper el tracking. Entender ese cambio probándolo, reportando y discutiendo es la forma más directa de pasar de consumidor a co-autor del modelo, y quien lo hace ahora llega temprano a la próxima década de Solid.

Un plan de dominio continuo

La experticia se oxida si no se riega, y un framework que se mueve —Solid 2.0 reescribe el runtime hacia una reactividad asíncrona transparente— la oxida más rápido. Un plan sostenible tiene cinco ejes, cada uno una práctica en presente continuo, no una tarea que se tacha.

Construye algo real y no trivial, porque solo un proyecto de verdad te enfrenta a las decisiones de arquitectura de las lecciones anteriores; los tutoriales no tienen deuda técnica ni casos límite, y ahí es donde de verdad se aprende.

Enseña lo que sabes —escribe, explica, responde en el Discord—, porque enseñar expone justo lo que creías entender y no: no hay auditoría más despiadada de tu modelo mental que tener que hacerlo comprensible a otro.

Lee la fuente cada cierto tiempo, empezando por el archivo de signals y reconstruyéndolo con tus manos, para que tu comprensión siga anclada al código real y no a una versión congelada en tu memoria.

Sigue el trabajo de quien empuja el modelo, en especial el desarrollo de Solid 2.0, que es hacia donde va todo; leer las discusiones de diseño te enseña no solo el qué, sino el porqué de cada decisión. Y contribuye desde lo pequeño para entrar en el bucle donde el framework se piensa, porque se aprende distinto desde dentro que desde fuera.

No es una lista de tareas que se completa: es una práctica que se mantiene, y el que la mantiene es experto de forma perpetua, no titular de un diploma que caduca.