Una decisión de UX que hice mal la primera vez
Esto empezó como un bug pequeño de funcionalidad faltante: tocar una tarjeta de lanzamiento en Discover no hacía nada. La solución en sí terminó siendo simple, pero primero construí la interacción equivocada, y esa es la parte más interesante.
Problema
Lo encontré mientras verificaba en el dispositivo la corrección de otro bug: las tarjetas de lanzamiento de la pestaña Discover eran puro display, sin manejador de toque, sin ninguna acción de agregar. Revisé el código y el propio comentario de documentación de la tarjeta lo delataba, literalmente decía que la acción de agregar a lista de reproducción estaba planeada para un issue anterior, junto con el gesto de deslizar “Not Interested.” Solo se construyó la mitad de eso.
Por qué este enfoque (intento uno)
La app ya tenía un método de servicio que hacía exactamente esto, agregar un álbum del catálogo a una lista de reproducción, sin necesidad de adaptación porque los elementos del feed de Discover ya son del tipo correcto. Conectarlo fue la parte fácil. La pregunta de diseño interesante era la interacción: ¿cómo dispara realmente esta acción quien usa la app?
Mi primer instinto fue buscar consistencia con el gesto “Not Interested” que ya existía en la misma tarjeta: agregar una segunda acción de deslizar, en el borde opuesto, con tinte verde e ícono de más. Calzaba con el modelo de interacción existente de la fila, no requería jerarquía de vistas nueva, y funcionaba, lo construí, escribí pruebas, lo instalé en un dispositivo físico y confirmé que funcionaba de principio a fin.
Contratiempos
Después lo usé de verdad por un tiempo, y estaba mal. En todas partes del resto de la app, Playlist, History, la acción equivalente funciona de la misma manera: se toca una tarjeta y aparece una hoja de detalle con botones. Discover pasó a ser la única pestaña donde había que saber que tocaba deslizar en vez de tocar. Optimicé para “el diff más pequeño en esta tarjeta” y me perdí la consistencia más importante: hacer que calzara con cómo el resto de la app ya manejaba esta misma interacción.
Esa es una lección real sobre encuadrar una decisión de UI desde el punto de referencia equivocado. Comparé la nueva acción contra su hermana en la misma tarjeta en vez de contra su contraparte en las otras pestañas. Ambos son argumentos legítimos de “calza con los patrones existentes,” pero solo uno de los dos sobrevive al uso real de la app, y la única forma de descubrirlo era usarla, no discutirlo desde el diff.
Implementación (intento dos)
Lo reconstruí bien: una hoja de detalle nueva y un view model nuevo, calcando deliberadamente casi línea por línea los dos que ya existen para Playlist y History, el mismo layout de encabezado (portada, título, artista, insignia, año), el mismo enum AddState (idle/adding/done/failed) que maneja el texto, ícono y tinte del botón, el mismo cableado de .sensoryFeedback para la confirmación háptica en el instante en que cambia el estado. La versión de Discover es más simple que sus hermanas porque no necesita una sección de sugerencias del mismo artista, todo el feed de Discover ya es las sugerencias.
Un hallazgo incidental mientras hacía esto: el código existente de agregar a lista de reproducción de History y mi código nuevo de Discover necesitaban una lógica idéntica para resolver la lista de reproducción vinculada y traducir un fallo a un mensaje accionable (“vincula una lista de reproducción en Settings,” “esta lista de reproducción no es tuya para editar,” y así). En vez de copiar y pegar por segunda vez, lo extraje a un pequeño archivo compartido que ambas funciones llaman ahora. Algo pequeño, pero del tipo de duplicación fácil de justificar saltarse en un diff de dos líneas, y mucho más difícil de justificar una vez que se ve el mismo bloque apareciendo dos veces.
Resultados
La suite completa quedó verde con 171 pruebas, incluyendo cobertura nueva para las tres ramas reales del view model de detalle de lanzamiento (agregar exitoso, fallo por lista de reproducción no vinculada, cerrar y descartar). Reconstruí e instalé de nuevo en un dispositivo físico por segunda vez y confirmé que la interacción real calza exactamente con Playlist y History.
Todo el desvío costó unos veinte minutos extra. Valió la pena, lanzar el patrón de interacción equivocado a una superficie de UI compartida es mucho más caro de notar y deshacer después que atraparlo durante una pasada en el dispositivo el primer día.
Lecturas relacionadas
La configuración que funcionaba perfecto y se sentía completamente rota
Un filtro solo se aplicaba tras reabrir la app, porque un TabView mantiene vivos los view models y congela el estado sembrado. La solución eliminó un concepto.
Una sección de tracklist, y por qué tomó 30 minutos
Un método de protocolo, un enum de estado reutilizado, una convención de enrutamiento que se mantuvo, y un límite de lint que forzó una división que valía la pena hacer de todos modos.
Recuperé un fix guardado en el stash, y una reproducción en vivo en mi teléfono me mostró un error distinto
Un stash apply limpio, una regla de SwiftLint que compara sintaxis en vez de rastrear consumo, y un bloqueo en tres pestañas que no era el error ya arreglado.
También te podría ser útil
Proton VPN
VPN comercial con filtrado NetShield e interruptor de apagado automático.
Como socio de Proton, obtengo ingresos por las compras que califican de los servicios de privacidad y seguridad de Proton (Pass, Mail, VPN, Drive).
Más informacióneSIM Airalo
eSIM de datos local para viajes - sin necesidad de cambiar una SIM física.
Este es mi enlace de referido de Airalo. Obtienes un descuento en tu primer eSIM y yo obtengo crédito de Airalo para el mío.
Más informaciónNordPass
Gestor de contraseñas del equipo detrás de NordVPN, con un plan gratuito.
Como afiliado de NordPass, obtengo ingresos por las compras que califican.
Más información