Cómo crear interfaces de usuario de JavaScript resistentes

 

 

 

  • Advanced Modern CSS Masterclass, with Manuel Matuzović
  • Design System Planning and Process, with Nathan Curtis

  • Índice
    1. ¿Por qué ser resiliente?
    2. Igualdad de errores
    3. Es mejor prevenir que curar
    4. Respondiendo a los errores
    5. Observabilidad
    6. Retrospectivas
    7. Pensamientos finales

    Aceptar la fragilidad de la web nos permite crear interfaces de usuario capaces de adaptarse a la funcionalidad que pueden ofrecer, sin dejar de brindar valor a los usuarios. Este artículo explora cómo la degradación elegante, la codificación defensiva, la observabilidad y una actitud saludable hacia las fallas nos equipan mejor antes, durante y después de que ocurra un error.

     

    Las cosas en la web pueden fallar: las probabilidades están en nuestra contra. Muchas cosas pueden salir mal: una solicitud de red falla, una biblioteca de terceros falla, una función de JavaScript no es compatible (suponiendo que JavaScript esté disponible), una CDN falla, un usuario se comporta inesperadamente (hace doble clic en un botón de envío), el La lista continúa.

    Afortunadamente, nosotros, como ingenieros, podemos evitar, o al menos mitigar, el impacto de las roturas en las aplicaciones web que creamos. Sin embargo, esto requiere un esfuerzo consciente y un cambio de mentalidad para pensar tanto en escenarios infelices como en escenarios felices.

    La experiencia del usuario (UX) no tiene por qué ser todo o nada, solo lo que es utilizable. Esta premisa, conocida como degradación elegante, permite que un sistema continúe funcionando cuando algunas partes de él no funcionan, de manera muy parecida a como una bicicleta eléctrica se convierte en una bicicleta normal cuando se agota la batería. Si algo falla, solo la funcionalidad que depende de eso debería verse afectada.

    Las interfaces de usuario deben adaptarse a la funcionalidad que pueden ofrecer y, al mismo tiempo, proporcionar el mayor valor posible a los usuarios finales.

    ¿Por qué ser resiliente?

    La resiliencia es intrínseca a la web .

    Los navegadores ignoran las etiquetas HTML no válidas y las propiedades CSS no compatibles. Esta actitud liberal se conoce como Ley de Postel, que Jeremy Keith transmite magníficamente en Resilient Web Design :

    "Incluso si hay errores en HTML o CSS, el navegador seguirá intentando procesar la información, omitiendo cualquier parte que no pueda analizar".

    JavaScript es menos indulgente. La resiliencia es extrínseca. Le indicamos a JavaScript qué hacer si sucede algo inesperado. Si una solicitud de API falla, recae en nosotros la responsabilidad de detectar el error y, posteriormente, decidir qué hacer. Y esa decisión impacta directamente en los usuarios.

     

    La resiliencia genera confianza con los usuarios. Una experiencia con errores refleja mal la marca. Según Kim y Mauborgne, la conveniencia (disponibilidad, facilidad de consumo) es una de las seis características asociadas con una marca exitosa, lo que hace que la degradación elegante sea sinónimo de percepción de la marca.

    Una UX sólida y confiable es una señal de calidad y confiabilidad, las cuales alimentan la marca. Un usuario que no puede realizar una tarea porque algo está roto, naturalmente, se enfrentará a una decepción que podría asociar con su marca.

    A menudo, las fallas del sistema se consideran "casos de esquina": cosas que rara vez suceden; sin embargo, la Web tiene muchas esquinas. Los diferentes navegadores que se ejecutan en diferentes plataformas y hardware, respetan nuestras preferencias de usuario y modos de navegación (Safari Reader/tecnologías de asistencia), y que se ofrecen a ubicaciones geográficas con diferentes latencia e intermitencia aumentan la apariencia de que algo no funciona según lo previsto.

    Igualdad de errores

    Al igual que el contenido de una página web tiene jerarquía, las fallas (las cosas que salen mal) también siguen un orden jerárquico. No todos los errores son iguales, algunos son más importantes que otros.

    Podemos clasificar los errores por su impacto. ¿Cómo es que XYZ no funciona impide que un usuario logre su objetivo? La respuesta generalmente refleja la jerarquía de contenido.

    Por ejemplo, una descripción general del panel de control de su cuenta bancaria contiene datos de diversa importancia. El valor total de su saldo es más importante que una notificación que le solicita que revise los mensajes dentro de la aplicación. El método de priorización de Moscú clasifica el primero como algo imprescindible y el segundo como algo que es bueno tener.

    Un ejemplo de información primaria versus secundaria. El saldo de la cuenta (£500) es información primaria integral para la experiencia del usuario, mientras que las notificaciones no leídas son una mejora no esencial (información secundaria). ( Vista previa grande )

    Si la información primaria no está disponible (es decir, si falla la solicitud de red), debemos ser transparentes e informar a los usuarios, generalmente mediante un mensaje de error. Si la información secundaria no está disponible, aún podemos brindar la experiencia principal (que es imprescindible) mientras ocultamos elegantemente el componente degradado.

    Cuando el saldo de la cuenta no está disponible, mostramos un mensaje de error. Cuando las notificaciones no leídas no están disponibles, simplemente eliminamos el recuento y la ventana emergente de la interfaz de usuario, preservando al mismo tiempo el enlace semántico a href='/notifications'al centro de notificaciones. ( Vista previa grande )

     

    Saber cuándo mostrar o no un mensaje de error se puede representar mediante un árbol de decisión simple:

    Los errores primarios deberían aparecer en la interfaz de usuario, mientras que los errores secundarios se pueden ocultar elegantemente. ( Vista previa grande )

    La categorización elimina la relación 1-1 entre fallas y mensajes de error en la interfaz de usuario. De lo contrario, corremos el riesgo de bombardear a los usuarios y saturar la interfaz de usuario con demasiados mensajes de error. Guiados por la jerarquía de contenido, podemos seleccionar qué fallas aparecen en la interfaz de usuario y qué sucede sin que los usuarios finales lo sepan.

    El hecho de que hayan ocurrido 3 errores (izquierda) no significa automáticamente que se deban mostrar 3 mensajes de error. Una acción, como un botón de reintento o un vínculo a la página anterior, ayuda a guiar a los usuarios sobre qué hacer a continuación. ( Vista previa grande )

    Es mejor prevenir que curar

    La medicina tiene un dicho que dice que más vale prevenir que curar.

    Aplicado al contexto de la creación de interfaces de usuario resistentes, evitar que ocurra un error en primer lugar es más deseable que tener que recuperarse de uno. El mejor tipo de error es el que no ocurre.

    Es seguro asumir que nunca se deben hacer suposiciones, especialmente cuando se consumen datos remotos, se interactúa con bibliotecas de terceros o se utilizan funciones de lenguaje más nuevas. Las interrupciones o los cambios de API no planificados junto con los navegadores que los usuarios eligen o deben usar están fuera de nuestro control. Si bien no podemos evitar que se produzcan roturas fuera de nuestro control, podemos protegernos contra sus efectos (secundarios).

    Adoptar un enfoque más defensivo al escribir código ayuda a reducir los errores del programador que surgen al hacer suposiciones. El pesimismo sobre el optimismo favorece la resiliencia. El siguiente ejemplo de código es demasiado optimista:

    const debitCards = useDebitCards();return ( ul {debitCards.map(card = { li{card.lastFourDigits}/li })} /ul);

    Se supone que existen tarjetas de débito, el punto final devuelve una matriz, la matriz contiene objetos y cada objeto tiene una propiedad denominada lastFourDigits. La implementación actual obliga a los usuarios finales a probar nuestras suposiciones. Sería más seguro y más fácil de usar si estas suposiciones estuvieran integradas en el código:

    const debitCards = useDebitCards();if (Array.isArray(debitCards) debitCards.length) { return ( ul {debitCards.map(card = { if (card.lastFourDigits) { return li{card.lastFourDigits}/li } })} /ul );}return "Something else";

    Usar un método de terceros sin verificar primero si el método está disponible es igualmente optimista:

    stripe.handleCardPayment(/* ... */);

    El fragmento de código anterior supone que el stripeobjeto existe, tiene una propiedad denominada handleCardPaymenty que dicha propiedad es una función. Sería más seguro y, por lo tanto, más defensivo si verificáramos estas suposiciones de antemano:

     

    if ( typeof stripe === 'object' typeof stripe.handleCardPayment === 'function') { stripe.handleCardPayment(/* ... */);}

    Ambos ejemplos comprueban que algo esté disponible antes de usarlo. Quienes estén familiarizados con la detección de características pueden reconocer este patrón:

    if (navigator.clipboard) { /* ... */}

    Simplemente preguntarle al navegador si es compatible con la API del Portapapeles antes de intentar cortar, copiar o pegar es un ejemplo simple pero efectivo de resiliencia. La interfaz de usuario puede adaptarse con anticipación ocultando la funcionalidad del portapapeles de navegadores no compatibles o de usuarios que aún no han concedido permiso.

    Ofrecer funcionalidad a los usuarios solo cuando sepamos que pueden usarla. Los botones de copiar al portapapeles (derecha) se muestran condicionalmente en función de si la API del portapapeles está disponible. ( Vista previa grande )

    Los hábitos de navegación de los usuarios son otro ámbito que escapa a nuestro control. Si bien no podemos dictar cómo se utiliza nuestra aplicación, podemos establecer barreras de seguridad que impidan lo que percibimos como "uso indebido". Algunas personas hacen doble clic en los botones, un comportamiento en su mayoría redundante en la web, pero que no constituye un delito punible. Recetas para Cookeo

    Hacer doble clic en un botón que envía un formulario no debería enviar el formulario dos veces, especialmente para métodos HTTP no idempotentes . Durante el envío del formulario, evite envíos posteriores para mitigar las consecuencias de la realización de múltiples solicitudes.

    Los usuarios no deben ser sancionados por sus hábitos o percances en la navegación. Evitar el envío de múltiples formularios debido a dobles clics intencionales o accidentales es más fácil que cancelar transacciones duplicadas en una fecha posterior. ( Vista previa grande )

    Evitar el reenvío de formularios en JavaScript junto con el uso aria-disabled="true"es más útil y accesible que el disabledatributo HTML. Sandrina Pereira explica con gran detalle Cómo hacer que los botones deshabilitados sean más inclusivos .

    Respondiendo a los errores

    No todos los errores se pueden prevenir mediante programación defensiva. Esto significa que responder a un error operativo (los que ocurren dentro de programas escritos correctamente) recae sobre nosotros.

    La respuesta a un error se puede modelar mediante un árbol de decisión. Podemos recuperar, retroceder o reconocer el error:

    Árbol de decisión que representa cómo podemos responder a los errores de tiempo de ejecución. ( Vista previa grande )

    Ante un error, la primera pregunta debería ser: "¿podemos recuperarlo?" Por ejemplo, ¿volver a intentar una solicitud de red que falló por primera vez tiene éxito en intentos posteriores? Los microservicios intermitentes, las conexiones a Internet inestables o la eventual coherencia son motivos para volver a intentarlo. Las bibliotecas de recuperación de datos como SWR ofrecen esta funcionalidad de forma gratuita.

     

    El apetito por el riesgo y el contexto circundante influyen en los métodos HTTP con los que se siente cómodo reintentando. En Nutmeg reintentamos lecturas fallidas (solicitudes GET), pero no escrituras (POST/ PUT/ PATCH/ DELETE). Múltiples intentos de recuperar datos (rendimiento de la cartera) son más seguros que modificarlos (volver a enviar un formulario).

    La segunda pregunta debería ser: si no podemos recuperarnos, ¿podemos ofrecer un recurso alternativo? Por ejemplo, si falla un pago con tarjeta en línea, podemos ofrecerle un medio de pago alternativo, como PayPal o Open Banking.

    Cuando algo sale mal, ofrecer una alternativa ayuda a los usuarios a ayudarse a sí mismos y evita callejones sin salida. Esto es especialmente importante para transacciones urgentes, como comprar acciones o contribuir a una ISA antes de que finalice el año fiscal. ( Vista previa grande )

    Las alternativas no siempre tienen que ser tan elaboradas, pueden ser sutiles. La copia que contiene texto que depende de datos remotos puede recurrir a texto menos específico cuando falla la solicitud:

    Las interfaces de usuario pueden adaptarse a los datos disponibles y aún así proporcionar valor. La frase más vaga (izquierda) todavía recuerda a los usuarios que las asignaciones del ISA caducan cada año. La oración más enriquecida (derecha) es una mejora para cuando la solicitud de red tiene éxito. ( Vista previa grande )

    La tercera y última pregunta debería ser: si no podemos recuperarnos o retroceder, ¿qué importancia tiene este fracaso (que se relaciona con el “Error de Igualdad”). La interfaz de usuario debe reconocer los errores principales informando a los usuarios que algo salió mal y al mismo tiempo proporcionar indicaciones prácticas, como ponerse en contacto con el servicio de atención al cliente o vincular a artículos de soporte relevantes.

    Evite mensajes de error inútiles. El útil mensaje de error (derecha) solicita al usuario que se comunique con CS, incluido cómo (teléfono/correo electrónico) y en qué horario operan para gestionar las expectativas. No es raro proporcionar errores con un identificador único al que los usuarios pueden hacer referencia al establecer contacto. ( Vista previa grande )

    Observabilidad

    La adaptación de las UI a algo que va mal no es el final. Hay otra cara de la misma moneda.

    Los ingenieros necesitan visibilidad sobre la causa raíz detrás de una experiencia degradada. Incluso los errores que no llegan a los usuarios finales (errores secundarios) deben propagarse a los ingenieros. Los servicios de monitoreo de errores en tiempo real, como Sentry o Rollbar, son herramientas invaluables para el desarrollo web moderno.

    Una captura de pantalla de un error capturado en Sentry. ( Vista previa grande )

    La mayoría de los proveedores de monitoreo de errores capturan automáticamente todas las excepciones no controladas. La configuración requiere un esfuerzo de ingeniería mínimo que rápidamente genera dividendos para un entorno de producción saludable y mejorado y MTTA (tiempo medio de reconocimiento).

    El verdadero poder surge cuando nosotros mismos registramos explícitamente los errores. Si bien esto implica un mayor esfuerzo inicial, nos permite enriquecer los errores registrados con más significado y contexto, los cuales ayudan a solucionar problemas. Cuando sea posible, busque mensajes de error que sean comprensibles para los miembros no técnicos del equipo.

     

    Las convenciones de nomenclatura ayudan a estandarizar los mensajes de error explícitos, lo que los hace más fáciles de encontrar/leer. El diagrama anterior utiliza el formato: [Dominio] Contexto — Problema. No es necesario ser ingeniero para comprender que una transferencia bancaria falló y que los equipos de pagos deben investigar (si aún no lo están haciendo). ( Vista previa grande )

    Extender el ejemplo anterior de Stripe con una rama else es el candidato perfecto para el registro de errores explícito:

    if ( typeof stripe === "object" typeof stripe.handleCardPayment === "function") { stripe.handleCardPayment(/* ... */);} else { logger.capture( "[Payment] Card charge — Unable to fulfill card payment because stripe.handleCardPayment was unavailable" );}

    Nota : este estilo defensivo no tiene por qué estar vinculado al envío del formulario (en el momento del error), puede ocurrir cuando un componente se monta por primera vez (antes del error), lo que nos da a nosotros y a la interfaz de usuario más tiempo para adaptarnos.

    La observabilidad ayuda a identificar las debilidades del código y las áreas que pueden reforzarse. Una vez que surge una debilidad, observe si y cómo se puede endurecer para evitar que vuelva a suceder lo mismo. Observe las tendencias y las áreas de riesgo, como las integraciones de terceros, para identificar qué podría incluirse en un indicador de función operativa (también conocido como interruptores de apagado).

    No todas las alternativas tienen que ser digitales. Esto es especialmente cierto para procesos que ya implican pasos manuales, como transferir una ISA de un banco a otro. Cuando todo está operativo (izquierda), los usuarios envían un formulario en línea que completa un PDF que imprimen y firman. Cuando el tercero sufre una interrupción o no funciona por mantenimiento (derecha), un interruptor de apagado permite a los usuarios descargar un formulario PDF en blanco que pueden completar (a mano), imprimir y firmar. ( Vista previa grande )

    Los usuarios advertidos de que algo no funciona se sentirán menos frustrados que aquellos sin previo aviso. Conocer las obras viales con antelación ayuda a gestionar las expectativas, lo que permite a los conductores planificar rutas alternativas. Cuando se enfrente a una interrupción (con suerte, descubierta mediante el monitoreo y no reportada por los usuarios), sea transparente.

    Evite descargar la observabilidad a los usuarios finales. Encontrar y reconocer problemas antes que los clientes conduce a una mejor experiencia de usuario. El banner de información anterior es claro, conciso y asegura a los usuarios que se conoce el problema y que se avecina una solución. ( Vista previa grande )

    Retrospectivas

    Es muy tentador pasar por alto los errores.

    Sin embargo, brindan valiosas oportunidades de aprendizaje para nosotros y nuestros colegas actuales o futuros. Es fundamental eliminar el estigma de la inevitabilidad de que las cosas salgan mal. En el pensamiento de caja negra, esto se describe como:

    "En organizaciones altamente complejas, el éxito sólo puede ocurrir cuando confrontamos nuestros errores, aprendemos de nuestra propia versión de una caja negra y creamos un clima donde sea seguro fallar".

    Ser analítico ayuda a prevenir o mitigar que vuelva a ocurrir el mismo error. Al igual que las cajas negras en la industria de la aviación registran incidentes, debemos documentar los errores. Como mínimo, la documentación de incidentes anteriores ayuda a reducir el MTTR (tiempo medio de reparación) en caso de que vuelva a ocurrir el mismo error.

    La documentación, a menudo en forma de informes RCA (análisis de causa raíz), debe ser honesta, reconocible e incluir: cuál fue el problema, su impacto, los detalles técnicos, cómo se solucionó y las acciones que deben seguir al incidente.

    Pensamientos finales

    Aceptar la fragilidad de la web es un paso necesario hacia la construcción de sistemas resilientes. Una experiencia de usuario más confiable es sinónimo de clientes satisfechos. Estar preparado para lo peor (proactivo) es mejor que apagar incendios (reactivo) desde el punto de vista empresarial, del cliente y del desarrollador (¡menos errores!).

    Cosas para recordar:

    • Las UI deben adaptarse a la funcionalidad que pueden ofrecer, sin dejar de ofrecer valor a los usuarios;
    • Piensa siempre en lo que puede estar mal (nunca hagas suposiciones);
    • Categorizar los errores según su impacto (no todos los errores son iguales);
    • Prevenir errores es mejor que responder a ellos (codificar a la defensiva);
    • Cuando se enfrente a un error, pregunte si hay disponible una recuperación o un respaldo;
    • Los mensajes de error que enfrenta el usuario deben proporcionar indicaciones procesables;
    • Los ingenieros deben tener visibilidad de los errores (utilizar servicios de seguimiento de errores);
    • Los mensajes de error para ingenieros/colegas deben ser significativos y proporcionar contexto;
    • Aprenda de los errores para ayudarnos a nosotros mismos y a los demás en el futuro.

    (vf, il)Explora más en

    • interfaz de usuario
    • experiencia de usuario
    • Flujo de trabajo
    • javascript





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Cómo crear interfaces de usuario de JavaScript resistentes

    Cómo crear interfaces de usuario de JavaScript resistentes

    Advanced Modern CSS Masterclass, with Manuel Matuzović Design System Planning and Process, with Nathan Curtis Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-como-crear-interfaces-de-usuario-de-javascript-resistentes-1114-0.jpg

    2024-05-24

     

    Cómo crear interfaces de usuario de JavaScript resistentes
    Cómo crear interfaces de usuario de JavaScript resistentes

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20