Con la primera etapa de la app cerrada, tocaba justo lo que anticipé en el post anterior: ese trabajo de detalle que nadie nota pero que sostiene todo lo demás.
Comenzó con un bug molesto. La app se congelaba «aleatoriamente» después de escribir un rato en el chat de registro y justo después de hacer scroll (no «crasheaba» literalmente, simplemente dejaba de responder). Como estaba probando la app con Xcode conectado, encontré el hilo principal atascado en el motor de dependencias de SwiftUI. La causa no era nada exótico: en cada re-dibujado de un mensaje con foto, la app volvía a decodificar la imagen desde cero, y para cada fecha volvía a crear un formateador de fecha nuevo. Con un historial de chat largo, ese costo se acumulaba hasta ahogar el hilo principal. (¿Recuerdan que dije que aún me faltaba mucho por aprender?) Un caché de imágenes decodificadas y un formateador reutilizado resolvieron el problema. Mirando hacia atrás es un bug relativamente simple de resolver, pero aquí es donde la falta de experiencia se nota, ya que la cantidad de pruebas que hice antes no fue menor. Fácil de arreglar una vez que sabes dónde mirar… El problema estaba precisamente en lo último.
Lo grueso de la semana fue el Historial. Desde el comienzo no me gustaba el layout. La idea es que la app sea simple, pero creo que me pasé con lo simple. Con el rediseño comenzaron los problemas. Si sacaba un ingrediente de una comida compuesta (las almendras del yogurt griego, por ejemplo) el resumen de esa comida se quedaba diciendo «yogurt griego con almendras» aunque las almendras ya no estuvieran. La pantalla de Historial editaba cada entrada suelta sin nunca tocar el resumen del grupo al que pertenecía.
Una solución era reconstruir el resumen completo, con la misma IA que arma las comidas nuevas, como ya se hace en la vista de Inicio. Tuve que descartarla: la IA recalculaba todo el grupo como si fuese una comida nueva, lo que provocaba una pérdida de precisión en ingredientes que nadie estaba corrigiendo. Terminé con un servicio aparte que regenera el resumen de forma determinística (sin IA y sin adivinar), solo uniendo en una frase los nombres de lo que efectivamente queda en el grupo. Además es más «barato» en términos de llamadas a la API key de Anthropic.
El primer rediseño de la pantalla agregó un chevron que expandía los ingredientes de una comida inline, en la misma tarjeta. Se veía bien en mi cabeza, pero al probarlo en el teléfono la lista expandida se sentía apretada, poco integrada. Lo descarté al día siguiente y después de muchas iteraciones, terminé integrando todo en una sola vista compartida por todas las tarjetas de comidas. (Simpleza). Tocas una comida y su tarjeta siempre se amplía y muestra el resumen, con la edición como un paso explícito después, no como punto de entrada. Es el mismo principio fundacional por el que pensé en construir esta app: la simpleza va primero. El problema es que a veces, al intentar implementar tantas cosas de una vez, como que uno se pierde en un bosque de opciones y termina añadiendo complejidad a algo que no lo necesita.
Cerré la semana reemplazando la cámara. Hasta entonces Calo usaba el picker de cámara nativo de iOS con la interfaz de siempre. Luego de un par de iteraciones la construí con AVFoundation directamente, usando la misma paleta de la app en los controles (el botón de disparo, el flash, el cambio de cámara). Quedó bien bonita y simple la verdad.
Una semana de harto trabajo y sin ninguna función nueva. Es loco eso, cuando uno ve una actualización en la App Store y reclama porque el desarrollador no muestra nada nuevo y todo es “corrección de errores”. Esa es la otra mitad del trabajo: que un resumen diga lo que realmente hay, que cancelar signifique cancelar de verdad, que una cámara se sienta propia y no prestada. Como en todas las disciplinas, son los pequeños detalles los que hacen que algo se vea pulido, bien terminado y no chapucero, aunque sea para un producto que vamos a usar sólo yo y mi esposa.









Deja un comentario