Saltar al contenido
Development

El callback que no podía decir qué había pasado

Por Victor Da Luz
svelterusttauridev-loggreenhouse

Dos errores pequeños y aparentemente sin relación, de la última revisión de código de Greenhouse, resultaron compartir una causa raíz que ya había “arreglado” una vez antes, en el mismo archivo, unos días atrás. Esa fue la parte útil de este caso, no el arreglo en sí, sino notar que el arreglo de la vez anterior no había terminado realmente el trabajo.

Error uno: importar un proyecto lo hacía desaparecer

Greenhouse permite adoptar una carpeta que ya existía en el disco dentro del pipeline de la app. Se abre un diálogo de “Switch vault,” que escanea la carpeta señalada, y se asigna cada subcarpeta sin reclamar a una etapa. Al hacer clic en “Import & Continue,” el elemento debería aparecer en la lista de trabajo.

No aparecía, si se importaba dentro del vault que ya se estaba usando. La importación en sí funcionaba bien, la fila de la base de datos se escribía, los archivos quedaban donde debían, pero el panel nunca se enteraba de que debía volver a mirar. Rastreando el problema: el componente selector tiene exactamente dos formas de avisarle a quien lo llama que algo pasó. Una se dispara cuando se apunta a una carpeta completamente nueva. La otra se dispara cuando no queda nada por decidir. Importar dentro del vault actual no es ninguna de las dos cosas. Es un evento real sin manera de anunciarse.

Error dos: ya había escrito la lección para esto

Acá es donde se puso interesante. Unos días antes había arreglado un error distinto en ese mismo componente, y había dejado una nota al respecto: cuando se extrae un componente que antes servía a un solo llamador hacia algo reusado por dos, hay que auditar cada callback en busca de contexto del que dependía en silencio. Ese arreglo anterior hizo que la señal de “no queda nada por decidir” se disparara solo cuando la situación realmente lo ameritaba, en vez de dispararse por error apenas se abría un diálogo.

Ese arreglo era correcto. También me dio una falsa confianza de que el diseño del componente ya era sólido, cuando en realidad todo lo que había arreglado era cuándo se disparaba una señal existente. No me había preguntado si el pequeño conjunto de señales que ofrecía siquiera alcanzaba para describir todos los eventos reales que el componente podía producir. No alcanzaba. “Acabo de cambiar a otra carpeta” y “acabo de importar algo dentro de la carpeta en la que ya estaba” son hechos distintos sobre el mundo, y el componente solo tenía espacio para decir uno de los dos.

El arreglo esta vez fue dejar de tratar el conjunto de señales como fijo y agregar una tercera, un callback específico que se dispara solo cuando realmente ocurrió una importación, conectado directamente a una simple actualización de datos. No enrutado a través del manejador de “vault switched,” que reinicia un montón de otro estado de interfaz que no tiene nada que ver con este caso. Volví a la nota sobre el primer arreglo y le agregué una sección, porque el segundo error no es una lección nueva, es la primera lección aplicada un nivel demasiado superficial: arreglar cuándo se dispara un callback no dice si hay suficientes callbacks para empezar.

Error tres, que no era un error

La misma revisión marcó una tercera cosa, y esta casi la arreglo antes de verificar que fuera real. Greenhouse tiene un previsualizador de audio integrado: se hace clic en un archivo, se abre un diálogo, y se puede escuchar sin salir de la app. Avanzar un proyecto mueve su carpeta en el disco, así que la teoría era: si el diálogo de previsualización está abierto y se avanza la etapa, el reproductor sigue apuntando a una ruta de archivo que ya no existe.

Excepto que eso no se puede hacer en realidad. El diálogo de previsualización usa el elemento nativo <dialog> del navegador, abierto con su método real showModal(), no un overlay hecho a mano. Ese método deja todo lo demás en la página verdaderamente inerte, incluido el botón “Confirm advance.” Es físicamente imposible hacerle clic mientras hay una previsualización abierta. Primero hay que cerrar la previsualización, lo cual ya limpia su estado. El error para el que estaba a punto de escribir código defensivo no podía ocurrir, porque la plataforma ya lo había descartado.

Aun así, quedaba un error real y adyacente por arreglar: la lista de archivos detrás de ese diálogo se mantenía montada todo el tiempo que la vista de detalle de un elemento estaba abierta, y solo se cargaba una vez, al inicio. Avanzar una etapa movía los archivos en el disco y la lista nunca se enteraba. Ese solo necesitaba una segunda consulta junto a la actualización existente, una vez confirmado que era el camino realmente alcanzable y no el bloqueado por el modal.

Lo que me queda de esto

Dos cosas, y tiran en direcciones un poco distintas. Primero: arreglar un error en un componente compartido es un buen momento para hacer una segunda pregunta que no se hace automáticamente, no solo “¿esto se dispara en el momento correcto ahora?”, sino “¿el vocabulario completo de señales de este componente alcanza para describir todo lo que puede hacer?”. La segunda pregunta implica más trabajo y es tentador saltársela una vez que el error visible desapareció. Segundo: un reporte de error que suena plausible vale diez minutos de verificar si el orden de eventos que describe siquiera es alcanzable, antes de escribir una sola línea de código defensivo para él. A veces la plataforma ya hizo el arreglo, y el trabajo real es confirmarlo, no sumarle más.

Lecturas relacionadas