Uso de hints en las interfaces de usuario

Al diseñar una interfaz de usuario la mahyor parte del peso de comunicación entre la interfaz y el usuario es a través del canal visual. Mediante un vistazo a una pantalla se puede intuir cómo utilizar ciertos elementos de la interfaz. Pero como no todas las personas tienen la misma capacidad de intuición ni la misma posibilidad de echar un vistazo a la pantalla debemos hacer uso de los distintos elementos de accesibilidad para hacer que la misma interfaz de usuario sea comprensible y usable para todas las personas.
A veces el uso de un control sólo se puede entender de forma visual como puede ser un interruptor deslizante para seleccionar un elemento más a la izquierda o más a la derecha, un botón de 3 estados o un cuadro de edición auto completable que permite realizar ciertas operaciones mientras se edita ese campo. En todos esos casos las personas con discapacidad visual pueden encontrar problemas a la hora de entender cómo utilizar dicho control. Para ayudar a este perfil de usuario la capa de accesibilidad permite incluir al control un texto de ayuda para entender cómo utilizar el control. Es lo que se conoce como hint o pista.

¿Qué son los Hints de Accesibilidad?

Los hints de accesibilidad son textos adicionales que proporcionan información contextual sobre un control de interfaz. Para los usuarios de lectores de pantalla. Estos hints pueden ser la diferencia entre una experiencia fluida y una frustrante. Por ejemplo, en una aplicación de banca móvil, un botón que simplemente dice «Enviar» podría no ser suficiente. Un hint podría agregar: «Enviar transferencia bancaria», proporcionando un contexto claro y específico.
Otro ejemplo podría ser un botón de tres estados cuyo hint podría indicar «pulse este botón para cambiar entre aceptado, pendiente y rechazado para actualizar el estado del pedido».

Implementación de Hints en Diferentes Plataformas

iOS

En iOS, los hints de accesibilidad se implementan utilizando el atributo accessibilityHint. Este atributo permite a los desarrolladores definir una cadena de texto que será leída por VoiceOver, el lector de pantallas de Apple, al final de toda la información del control.

Por ejemplo, un botón que tiene un icono de lápiz para editar puede no ser claro para todos los usuarios, pero al añadir un AccessibilitHint con el valor «Pulsa dos veces para modificar el valor de este campo»”, se proporciona la información necesaria para el usuario.

Android

En Android, los hints de accesibilidad se consiguen con el atributo android:hint en el fichero XML de la actividad. Este hint proporciona una descripción de lo que un control hace o lo que se espera que el usuario haga con él. Por ejemplo, un campo de entrada de texto puede tener un hint como “Introduce tu nombre completo”, lo cual es leído por TalkBack (el lector de pantalla de Android) para guiar al usuario.

HTML

En HTML, los hints se implementan con los atributos aria-description y aria-describedby.

El atributo aria-description proporciona una descripción directa del elemento, mientras que aria-describedby hace referencia a otro elemento en la página que contiene una descripción más detallada. Por ejemplo, un botón de búsqueda podría tener un aria-description=»Use este botón para buscar en todo el sitio web», y aria-describedby podría apuntar a un párrafo cercano al campo de búsqueda que explique cómo funciona la búsqueda en el sitio web.

Importancia de los Hints en la Accesibilidad

Estos atributos impactan en la accesibilidad de la interfaz de la siguiente forma:

  1. Claridad y Contexto: Los hints proporcionan información adicional que ayuda a los usuarios a entender la función de un control. Esto es especialmente importante para controles que solo tienen iconos o textos ambiguos.
  2. Mejora de la Usabilidad: Al proporcionar instrucciones claras sobre cómo utilizar un control, se mejora la usabilidad de la aplicación o sitio web, haciendo que la experiencia sea más intuitiva y menos frustrante para los usuarios con discapacidades visuales.
  3. Inclusión: Al implementar hints de accesibilidad, los desarrolladores están tomando pasos activos hacia la inclusión digital, asegurándose de que sus productos sean utilizables por el mayor número posible de personas.

Problemas Comunes con los Hints

A pesar de su importancia, los hints de accesibilidad no están exentos de problemas. Algunos de los desafíos más comunes incluyen:

  1. Hints Redundantes: A veces, los desarrolladores añaden hints que repiten información que ya está clara en el contexto visual, lo que puede resultar en una sobrecarga de información para el usuario de un lector de pantalla. Por ejemplo, un botón con un texto visible “Buscar” no necesita un hint adicional que diga “Botón de búsqueda”.
  2. Falta de Actualización: Los hints pueden volverse obsoletos si no se actualizan junto con cambios en la interfaz. Esto puede llevar a confusión si un hint describe una funcionalidad que ya no existe o que ha cambiado.
  3. Hints Incompletos: No proporcionar suficiente información es otro problema. Un hint demasiado breve puede no dar el contexto necesario. Por ejemplo, un hint que solo dice “Enviar” sin más detalles podría no ser útil en una aplicación con múltiples funcionalidades de envío.
  4. Uso Incorrecto de los Atributos: En HTML, confundir aria-description con aria-describedby puede llevar a que los usuarios de lectores de pantalla no reciban la información adecuada. Es crucial usar cada atributo de forma correcta para asegurarse de que la información se transmite adecuadamente.
  5. Problemas de personalización del lector de pantallas: algunos usuarios ciegos deshabilitan la lectura de estos elementos para dar mayor agilidad a su experiencia de uso. Esto implica que en el hint sólo se debe incluir la información relacionada con el control para evitar que el usuario pierda información vital de otra parte de la interfaz.

Buenas Prácticas para el Uso de Hints

Para maximizar la efectividad de los hints de accesibilidad, es importante seguir algunas buenas prácticas:

  1. Ser Claro y Conciso: Proporcionar descripciones claras y directas que sean fáciles de entender. Evitar la jerga técnica y centrarse en el propósito del control.
  2. Actualizar Regularmente: Asegurarse de que los hints se actualizan junto con cualquier cambio en la interfaz de usuario para evitar descripciones obsoletas.
  3. Consistencia: Mantener una terminología y un estilo consistentes en todos los hints para evitar confusión.
  4. Seguir los estilos definidos en la guía de interfaces del fabricante: Apple y Google tienen recomendaciones sobre el estilo de lenguaje a emplear en los hints.

Cómo notificar de forma apropiada un error en una aplicación o servicio

A la hora de mejorar y mantener un producto software los desarrolladores utilizan el feedback proporcionado por los usuarios a través de lo que se conoce como bug report o feedback report. Un bug report es un mensaje de un usuario al desarrollador indicando que hay un problema en una aplicación.

Este mensaje se puede enviar a través de correo electrónico, mediante una plataforma web de gestión de errores, a través de chat o a través del canal que el desarrollador haya proporcionado para la comunicación con los usuarios.

Un bug report efectivo

En muchas ocasiones los reportes de error enviados por los usuarios son totalmente inútiles y poco efectivos ya que se limitan a mensajes del tipo la app no funciona. Es evidente que si se envía un reporte de error es porque el usuario ha encontrado que algo no funciona pero los desarrolladores, por ahora, no podemos leer el pensamiento de los usuarios por lo que es necesario dar más detalles sobre qué no funciona para encontrar respuesta a la pregunta de por qué no funciona y cómo hace el usuario para que no funcione ya que los desarrolladores antes de publicar sus aplicaciones realizan multitud de pruebas de uso y puede que conocer cómo utilizan su aplicación otras personas les permita mejorar el uso de la misma.

Además, decir que la app no funciona es algo muy general. Una app pequeña tiene entre 4 y 15 pantallas por lo que es de agradecer un poco más de información.

Qué incluir en un reporte de error

A la hora de enviar un reporte de error es muy recomendable incluir los siguientes apartados:

Descripción breve del problema

En un par de párrafos describir qué error sucede. Se recomienda incluir el nombre de la aplicación, en qué pantalla sucede y cómo llegó a esa pantalla.

Paso a paso

Incluir una lista de pasos desde que se abre la aplicación hasta que se obtiene el error o el comportamiento no esperado.

También se debe incluir un paso indicando que se activa el lector de pantallas, el magnificador o cualquier otro producto de apoyo que se esté utilizando ya que a veces los errores sólo suceden con un producto de apoyo.

Además, si el producto de apoyo o la aplicación tiene alguna personalización o ajuste especial que provoque el problema también es necesario indicarlo.

Resultados esperados y resultados obtenidos

Este apartado sirve para indicar qué esperaba el usuario que sucediese y qué es lo que sucede realmente. A veces el problema no es de software sino de lenguaje empleado. El usuario entendió que debería pasar una cosa pero el desarrollador no se explicó bien en el manual o las instrucciones en la aplicación. Este tipo de informes de error permiten solucionar este tipo de problemas de malentendidos o para comprender qué experiencia de uso tienen los usuarios ante ciertas situaciones provocadas por sus aplicaciones.

Los resultados esperados y resultados obtenidos suelen ser un par de párrafos describiendo ambos elementos.

Observaciones

Este apartado suele ser un texto beve donde el usuario puede aportar más información sobre, por ejemplo, si está utilizando el dispositivo con una configuración determinada (por ejemplo un iPhone configurado en Español de USA con modo oscuro y con auriculares), el modelo de su dispositivo o si tenía algún dispositivo más conectado.

Adjuntos al reporte

Adjunto al reporte de errores es recomendable incluir un adjunto con un informe de comportamiento o fichero de log que permita al desarrollador ver el comportamiento interno de la aplicación cuando sucedía el problema.

Si el apartado de paso a paso es muy detallado no es necesario incluir ningún adjunto a menos que el problema lo tenga un usuario en concreto y pueda ser por una configuración muy concreta o un fallo colateral en ese dispositivo concreto. Estos ficheros de log permiten encontrar esa información tan concreta que no es evidente ni para el usuario ni para el desarrollador. 

En la mayoría de ocasiones se piden estos ficheros en una segunda comunicación sólo si el desarrollador no ha podido reproducir el problema reportado por el usuario y tras seguir el paso a paso indicado.

Siempre con educación

Es algo que puede parecer evidente cuando nos comunicamos con otra persona pero es algo que muchas veces se olvida. Si un usuario espera que otra persona atienda a su mensaje con buena disposición es necesario un trato cordial y sin caer en insultos o palabras despectivas hacia la persona que desarrolla el software, su inteligencia o su progenie.

En varias ocasiones he desechado o ignorado reportes de error por estar mal estructurados, no aportar información suficiente o utilizar un lenguaje inapropiado. Y como yo conozco a muchos desarrolladores que hacen lo mismo ya que se considera que ese tipo de feddback no es beneficioso para el software.

Buscando el entendimiento

A veces también hay un problema de comunicación entre el usuario y el desarrollador por el lenguaje empleado. Puede que el usuario no sepa hablar francés y el desarrollador no sepa hablar japonés. En estos casos siempre es recomendable utilizar un idioma neutral, siendo el más común en el desarrollo de software utilizar inglés, y utilizando una herramienta de traducción incluir dentro del texto un aviso indicando que la persona habla en un idioma concreto y que este texto ha sido traducido al inglés gracias a una herramienta de traducción. Esto permite a ambas partes estar atentos a posibles malentendidos a causa de un error en la traducción.

Tests dentro de la ingeniería del software

Dentro de la mayoría de metodologías de diseño y desarrollo de software existe un apartado enfocado a las comprobaciones de las funciones, aspecto y comportamiento de una aplicación. Es lo que se conoce como testing dentro del proyecto.

Beneficios del testing

Dentro de la multitud beneficios que aporta realizar testing en nuestro proyecto se encuentran los siguientes.

  • Se pueden realizar pruebas específicas y generales del comportamiento de clases y funciones de nuestro proyecto. De esta forma podemos validar que las funciones y clases que desarrollamos dentro de nuestro proyecto cumplen los requisitos definidos por el documento de análisis.
  • Se pueden realizar pruebas completas de una experiencia de usuario. De esta forma podemos verificar que nada se ha roto cuando añadimos algún elemento nuevo a nuestro proyecto.
  • Las pruebas de uso de la aplicación se pueden automatizar para que nuestro ordenador compruebe que la aplicación funciona como se espera.
  • Además permite automatizar otros procesos que pueden resultar laboriosos o tediosos como la toma de capturas de pantalla, validación del aspecto visual de cada pantalla de la aplicación e incluso se pueden crear comprobaciones de accesibilidad en algunas plataformas para la detección temprana de barreras de accesibilidad.

Problemas del testing

Incluir testing en nuestro proyecto implica la aparición de los siguientes problemas, sobre todo si el equipo de desarrollo no está acostumbrado al uso de testing:

  • Incremento en los costes de organización y tiempo. Las pruebas o tests no se planifican ni se escriben solas. Es necesario organizar el plan de trabajo para que el testing sea correctamente incluido en la metodología de trabajo utilizada por el equipo dentro del proyecto.
  • Prevención de falsos errores. Cuando se realizan cambios visuales o funcionales dentro de una ventana o una sección de nuestra aplicación todos los tests relacionados con dicha pantalla fallarán. Es necesario que algún miembro del equipo actualice esos tests para que acepten los nuevos cambios y validar cuales son los nuevos comportamientos y aspectos válidos para el proyecto.
  • No existe la fiabilidad al completo. Aunque podamos pensar que un proyecto software siempre se comportará igual en cualquier situación cuando el proyecto es complejo también aumenta la complejidad para cubrir todos los posibles casos de uso con los tests. Incluso así es posible que nuestro conjunto de tests no detecte algún posible error o problema de funcionamiento de nuestra aplicación. Cuando esto sucede es necesario ampliar el número de tests para verificar que el error detectado no vuelva a ocurrir.

Tipos de testing

Dentro de la creación y mantenimiento de un proyecto de software existen distintas necesidades de comprobación por esta razón existen diversos tipos de testing.

Cada tipo de testing tiene un objetivo claro que ayuda a detectar y solucionar un tipo de problema específico del proyecto.

Tests funcionales

Este tipo de test comprueba si la funcionalidad de un método o función se adapta al comportamiento esperado. De esta forma podemos comprobar si una función de conversión de divisas funciona como se espera o si el cálculo de el total del precio de un pedido no comete errores.

Dentro de este tipo de tests encontramos los tests unitarios, tests de aceptación, tests de integración y tests de regresión.

Tests no funcionales

Este tipo de test representa  las pruebas que se realizan en la aplicación o producto y que no están relacionadas con el código del proyecto.

Algunas de estas pruebas son las pruebas de rendimiento, las pruebas de carga y las pruebas de estrés.

Regla YAGNI – You aren’t gonna need it

La última de las 5 reglas para escribir software simple y robusto es la regla de YAGNI. Su acrónimo traducido dice: no lo vas a necesitar.

En muchas ocasiones cometemos el error de hacer sobreingeniería en un proyecto. Esto significa que el cliente nos ha pedido una calculadora para hacer sumas y terminamos desarrollando una hoja de cálculo con soporte para funciones y un lenguaje propio de scripting. Esto provoca que el mantenimiento y el esfuerzo para desarrollar y mantener el proyecto se ha sobredimensionado de forma incontrolada e innecesaria.

Para evitar caer en este código innecesario o código YAGNI debemos centrarnos en los requerimientos del producto final, no desarrollar código que no se esté utilizando en el proyecto, eliminar el código comentado (Si está comentado es que no es necesario) y utilizar ciertos patrones de trabajo como TDD (Test Driven Development) o trabajar con PullRequests pequeñas enfocadas en aspectos muy específicos de un requerimiento o característica del proyecto. También realizar procesos de refactorización del código al terminar un plazo de entrega o el desarrollo de un módulo facilita la desaparición de código YAGNI.

Regla SOC – Separation of concerns

Dentro de las reglas para escribir software simple y robusto tenemos la regla de SOC cuyo acrónimo significa Separation of concerns. Esto se traduce como separación de intereses. Este término de ingeniería fue creado por Edsger Dijkstra en un artículo para indicar la necesidad de centrar la atención en aspectos específicos dentro de las distintas estructuras de manipulación de la información dentro del software. Esta separación de intereses dentro del software se puede aplicar a nivel de arquitectura del proyecto y a nivel de codificación de los métodos y funciones.

Arquitectura de intereses

A nivel de arquitectura debemos agrupar los distintos intereses dentro de módulos o microservicios. Cada módulo o servicio deberá encargarse de un aspecto del proyecto.

Se busca que cada módulo o microservicio sea independiente y tengan claras sus responsabilidades.

Dentro de la modularización del código se aplican patrones de diseño como MVC (Modelo vista controlador), MVP (Modelo vista presentador) y patrones de diseño similares. Esta forma de organizar el código nos permite diferenciar cláramente las clases relacionadas con el modelo de datos, la interfaz de usuario y la forma de presentar y manipular los datos en la interfaz de usuario. 

Aplicando estos patrones de diseño a la hora de modularizar nuestro código podremos realizar modificaciones en la interfaz de usuario sin necesidad de afectar al modelo de datos o a la lógica de negocio ya que las responsabilidades de cada parte del módulo están conceptualmente definidas.

Separación del código por intereses

Para separar el código por intereses se debe realizar un ejercicio de análisis observando desde el punto más alto de abstracción de nuestro proyecto, tanto en funcionalidad como en la información que se manipula, hasta delimitar la responsabilidad y relación entre las distintas clases y módulos del proyecto.

Con este esfuerzo se busca obtener las siguientes ventajas: eliminar la posible duplicación en la lógica de negocio, ampliar la capacidad de mantenimiento del proyecto, incremento de la cohesión entre clases y reducción del acoplamiento entre clases y módulos.

Una vez realizado este análisis se aplican distintos paradigmas de programación como la programación orientada a aspectos, arquitectura hexagonal, inyección de dependencias y la separación de métodos por responsabilidad.

Regla LOD – Law of Demeter

Una de las reglas para escribir software simple y robusto que también podemos aplicar a otros aspectos de la vida es la regla de Demeter. Esto es lo que significa LOD: law of Demeter.

Esta regla se resume en el concepto de: no hables con desconocidos.

Dentro de la ingeniería de software esta regla representa al principio del mínimo conocimiento.

Este principio nos dice que una función o método X perteneciente a un objeto Y sólo puede llamar a otros métodos o funciones pertenecientes al objeto, un parámetro del método X, cualquier objeto creado dentro del método X o cualquier propiedad definida dentro del método X.

Esto establece que la comunicación del método X se limita al dominio de su objeto contenedor o al propio dominio del método X.

De forma más comprensible este principio nos permite escribir un método de forma que cualquier información que el método necesite consultar o manipular estará dentro del propio código del método o dentro del código de la clase que lo contiene. De esta forma podemos detectar fácilmente posibles errores o seguir el movimiento de la información que manipula ese método.