Introducción a UI: Definiciones iniciales

Definiciones iniciales de la materia

¿Qué es interfaz de usuario?

Es todo lo que permite a un usuario interactuar con el sistema: esto incluye componentes lógicos (software) y físicos (hardware). Interfaz de Usuario también se puede abreviar por sus siglas en inglés: UI (User Interface) y en general se suele hablar de la interfaz gráfica como la parte de presentación de una aplicación.

¿Cuál es el objetivo de la materia?

Naturalmente, el objetivo de la materia es aprender a programar y diseñar interfaces de usuario. Sin embargo, la construcción de interfaces de usuario presenta muchos aspectos distintos y por eso conviene entender en cuáles vamos a hacer foco.

En primer lugar, cuando decimos "diseño", nos referimos a diseño de software. En el desarrollo de interfaces diseño podría también interpretarse como diseño gráfico, sin embargo eso tiene que ver menos con esta materia. Nos enfocamos en estudiar la interfaz desde el punto de vista de un programador. Por eso nos interesa entender cómo aplicamos los conceptos de diseño que ya sabemos a las interfaces de usuario y nos interesa aprender técnicas de programación o patrones de diseño específicos para las interfaces de usuario. Otros temas relacionados con las interfaces de usuario pero más enfocados a la funcionalidad o la usabilidad, aparecen en esta materia de un modo lateral.

Dentro de los múltiples enfoques que existen para construir interfaces de usuario, vamos a elegir algunos. Para describir exactamente cuáles son los focos que nos interesan nos falta introducir varias definiciones todavía, pero los podemos nombrar para que comiencen a sonar  en nuestras mentes: aplicaciones de escritorio basadas en eventos, aplicaciones web tradicionales, aplicaciones web orientadas a componentes, rich internet clients, y aplicaciones para dispositivos móbiles.

Nuestro objetivo también es concentrarnos en producir aplicaciones que se destaquen por sus cualidades de mantenibilidad, flexibilidad, claridad, robustez, entre otras. En el ámbito específico de las interfaces de usuario, un criterio importante será separar la responsabilidad correspondiente a la interfaz de usuario de la lógica de dominio.  Si bien no debemos descartar otras cualidades como performance o seguridad, consideramos conviene ponerle menos preponderancia y tal vez postergarlas un poco, para estudiarlas una vez que tengamos claros los conceptos básicos. Nos vamos a enfocar fundamentalmente en técnicas orientadas a objetos, entre otros motivos porque creemos que son muy útiles para lograr las cualidades de software que nos interesan.

Primer ejemplo

Generamos un primer ejemplo para empezar a entender dónde poner cada responsabilidad. Queremos armar la pantalla de inscripción a una materia de la facultad (p.ej: el curso de Algoritmos 3). 
  • La primera pregunta que podemos hacernos es: ¿para quién es esta pantalla? 
    • Podría ser para el departamento de alumnos. 
    • Pero también podrían ser los alumnos los que traten de inscribirse.
  • La pantalla (o vista) tiene controles:
    • Hay una grilla de alumnos anotados al curso, la grilla me permite mostrar información que está en una colección (no es la única forma, como veremos más adelante).
    • Para poder inscribir a un alumno a la materia, necesitamos definir una acción. ¿Qué nos sirve para poder disparar una acción? Un botón, claro. 
    • Aquí vemos que hay relaciones entre lo que queremos lograr y los controles visuales asociados, esto lo veremos la clase que viene como binding.
    • También podríamos buscar algún alumno anotado por nombre (o legajo). Eso implica un control textbox y un botón buscar que dispara la acción de búsqueda.
¿Siguen existiendo objetos de negocio? Claro, el alumno, la materia y el curso son objetos candidatos para el dominio de mi aplicación. 


Definiendo responsabilidades:
  • ¿Qué hace el botón "Buscar"? 
    • Le pide los alumnos inscriptos al curso 
    • Después se "llena la grilla": cada columna se asocia a un atributo del alumno (legajo, nombre y demás cosas que quiera mostrar).
  • ¿Qué hace el botón "Inscribir alumno"?
    • Ah, este es más complejo: para inscribir un alumno a una materia tenés que ir a una nueva pantalla para seleccionarlo de una lista de alumnos regulares de la carrera. No importa ahora cómo se resuelve, sabemos que si no tenemos el alumno no podemos seguir con el caso de uso.
    • Una vez que tenemos el alumno, podemos decirle al objeto de negocio Curso que agregue ese alumno.
    • Pero no alcanza con eso si queremos que el cambio sea persistente. Aquí aparece un nuevo objeto, el CursoHome que modela "el lugar donde viven los cursos". Los Home también se conocen como DAO (Data Access Object) o repositorio, y la principal responsabilidad es recuperar o actualizar objetos. A ese CursoHome le enviamos el mensaje update o actualizar.
    • Y finalmente volvemos a la pantalla original, donde podríamos refrescar la grilla para agregar el alumno recientemente inscripto
Para profundizar un poco más, pueden leer el artículo Elementos a tener en cuenta al programar UI.

  • Algunas cosas que surgen cuando pensamos en la interfaz:
    • A veces está bueno prototipar las pantallas porque surgen cuestiones del negocio: un administrador debe seleccionar el alumno para luego incorporarle materias. El alumno tendría "grisada" (inhabilitada) esta opción, salvo que el negocio determine que un alumno puede inscribir a otro. 
    • La navegación bidireccional en objetos es fácil de lograr: un curso de una materia tiene n inscriptos y podríamos hacer que el alumno conozca una colección de cursos en los que participa. Lograr la navegación visual (cursos de un alumno, alumnos de un curso) requiere un trabajo adicional y no es trivial.
    • Inscribir un alumno a un curso es sencillo: curso.inscribir(alumno). La lógica que sigue la pantalla, sin embargo, es mucho más compleja, tengo que guiar al usuario para que no elija dos veces el mismo alumno, que el alumno sea regular, las materias que puede elegir son las que les corresponde según la correlativa, tengo que tener cuidado en dónde está posicionado el usuario para ver qué opciones puede elegir, si la inscripción de un alumno navega hacia una nueva pantalla tengo que tener cuidado que no vuelva a la grilla y quiera volver a dar "Inscribir a un alumno" nuevamente. No es verdad que si el dominio está bien construido la presentación se hace sola.

Presentación y negocio

En particular en algo3 vamos a tratar de no mezclar ideas de presentación con negocio. Esto en nuestro ejemplo sería que la pantalla de inscripción de alumnos va a conocer objetos alumno, esto está bien que así sea, no quiero evitar que se conozcan, sólo quiero eliminar relaciones que perjudiquen la mantenibilidad del sistema. O sea, separar la lógica para definir la interacción con el usuario y la lógica propia del dominio. ¿Por qué?
  • porque no quiero que mi dominio se vea afectado por cuestiones tecnológicas.
  • porque eso me lleva a perder cohesión en los objetos de presentación, que además de encargarse de mostrar la información tienen que atacar cuestiones de negocio. Entonces en dos pantallas distintas tengo que repetir la misma validación o el mismo comportamiento. Por ejemplo: definimos cupos para anotarse en un curso (ej: en algoritmos 3 el máximo es 3). Si yo codifico la validación en la pantalla que definí anteriormente, y construyo una pantalla para el alumno para que le muestre el listado de materias y un link que diga "Inscribirse", tengo que repetir la validación del cupo en las dos pantallas. Eso es lo que queremos evitar.
  • porque tengo más restricciones a nivel usuario y tecnológicos del lado de la UI (es la parte más compleja y la menos madura, cuesta encontrar buenas abstracciones)

Pasamos en limpio la arquitectura general de una aplicación en Algo3

Separación entre vista y modelo: queremos que vista y modelo se conozcan pero sin estar altamente acopladas (recordamos cohesión y acoplamiento). La próxima clase veremos cómo implementar eso.

Tenemos objetos con responsabilidades específicas:
  • Vista: es un objeto dependiente de la tecnología, se puede construir
    • en forma visual
    • en forma programática o con un DSL específico
  • Controller: es el que sabe qué pasa cuando el usuario presiona el botón Aceptar, o cuando el usuario selecciona el combo de países, o cómo se relaciona la propiedad de un objeto de dominio con un control de la vista.
  • Dominio: son los objetos que hasta ahora habíamos trabajado en Algoritmos 2: la lista de correo, un usuario, la regla de un firewall, etc.
  • Home/DAO/Repositorio: objeto que hace consultas o actualizaciones contra un medio persistente (el lugar donde viven los objetos, sea en memoria, archivo o lo que fuera), por eso la palabra "home". La palabra DAO se asocia mucho con una base de datos, por eso nos gusta más hablar de Homes, porque desde afuera de estos objetos no nos interesa saber cómo se almacenan. Mensajes que entienden los homes:
    • buscar
    • agregar
    • eliminar
    • actualizar / modificar
  • Hay otros objetos posibles pero por el momento nos quedamos con éstos
    • objetos que manejan transacciones, para asegurarme que múltiples pasos se dan todos a la vez o ninguno
    • objetos log de auditoría
    • objetos que se encargan de la seguridad
    • objetos application model o view model que veremos en un par de clases
Pueden leer un poco más en este artículo.

Clasificación de las interfaces de usuario

Una aplicación puede pensarse desde la óptica del
  1. cliente: el que realiza pedidos
  2. servidor: el que responde a esos pedidos
Por lo general, el cliente es un componente local, es decir, una máquina a la cual accede cada usuario. El servidor suele ser una máquina conectada en red a todos los clientes, que concentra esos pedidos y se encarga de responderlos.



Es decir, la separación puede ser lógica (en el caso en que el cliente y el servidor son componentes ubicados físicamente en la misma máquina) o puede haber una separación lógica y física (como se muestra en el diagrama de arriba).

¿Qué tipo de pedidos hace el cliente?
Esto depende de la arquitectura sobre la cual trabajemos:
  1. Aplicación centralizada
  2. Aplicación distribuida (Cliente/Servidor)

Aplicación centralizada

El cliente tiene poca o nula inteligencia. El servidor tiene muchas responsabilidades, esto es:
  • recibe los parámetros (para validarlos y transformarlos)
  • procesa las acciones de negocio
  • transforma los resultados de esas acciones y
  • genera la visualización que va a obtener el cliente como respuesta.
Estos sistemas eran los preponderantes hasta mediados de los '80, la configuración tradicional eran "terminales bobas" o programas que las emulaban y un mainframe con grandes capacidades que actuaba como servidor.  Esquemas parecidos podrían ser programas que solamente capturen parámetros y los envíen al servidor que haga todo el procesamiento, incluyendo la "renderización" (1) de la respuesta. Del lado del cliente casi no hay lógica, ni de presentación ni de negocio.

(1) renderizar en este contexto tiene que ver con la forma en que se presenta la información al usuario

Aplicaciones distribuidas

Una aplicación con distintos componentes que se ejecutan en entornos separados, normalmente en diferentes plataformas conectadas a través de una red. Las típicas aplicaciones distribuidas son de dos niveles (cliente-servidor), tres niveles (cliente-middleware-servidor) y multinivel.

Cliente / Servidor

A comienzos de los noventa crecieron las capacidades de las máquinas que actuaban como cliente en las empresas, esto permitió pensar un esquema en el cual cada cliente se encargaba de la lógica de presentación mientras que la lógica de negocio se manejaba en el servidor, en general porque era una forma fácil de compartir la información que cada cliente iba generando.

La separación entre cliente y servidor es una separación de tipo lógico, donde el servidor no se ejecuta necesariamente sobre una sola máquina ni es necesariamente un sólo programa. Los tipos específicos de servidores  incluyen los servidores web, los servidores de archivo, los servidores del correo, etc. Mientras que sus propósitos varían de unos servicios a otros, la arquitectura básica es la misma.
En la arquitectura C/S el remitente de una solicitud es conocido como cliente. Sus características son:
  • Es quien inicia solicitudes o peticiones, tienen por tanto un papel activo en la comunicación (dispositivo maestro o amo).
  • Espera y recibe las respuestas del servidor.
  • Por lo general, puede conectarse a varios servidores a la vez.
  • Normalmente interactúa directamente con los usuarios finales mediante una interfaz gráfica de usuario.
Al receptor de la solicitud enviada por cliente se conoce como servidor. Sus características son:
  • Al iniciarse esperan a que lleguen las solicitudes de los clientes, desempeñan entonces un papel pasivo en la comunicación (dispositivo esclavo).
  • Tras la recepción de una solicitud, la procesan y luego envían la respuesta al cliente.
  • Por lo general, aceptan conexiones desde un gran número de clientes (en ciertos casos el número máximo de peticiones puede estar limitado).
  • No es frecuente que interactúen directamente con los usuarios finales.

Peer to peer

Otra alternativa consiste en la red peer-to-peer (P2P), donde cada equipo actúa como cliente o servidor dependiendo de si hace un pedido o lo responde (consumer/producer). No existe el servidor como equipo de sincronización, sino que cada equipo mantiene su propio estado:


Ejemplos de aplicaciones peer to peer son Napster, eMule, Skype, entre otras.

Ventajas de la visión Cliente/Servidor

  • Centralización del control: los accesos, recursos y la integridad de los datos son controlados por el servidor de forma que un programa cliente defectuoso o no autorizado no pueda dañar el sistema. Esta centralización también facilita la tarea de poner al día datos u otros recursos (mejor que en las redes P2P).
  • Escalabilidad: se puede aumentar la capacidad de clientes y servidores por separado. Cualquier elemento puede ser aumentado (o mejorado) en cualquier momento, o se pueden añadir nuevos nodos a la red (clientes y/o servidores).
  • Dado que hay una cierta independencia entre clientes y servidores, es posible reemplazar, reparar, actualizar o trasladar alguno de ellos con un bajo impacto, siempre y cuando ciertas variables se mantengan estables (debe estar un servidor activo, hay que asegurar el enlace entre los nodos, etc.)
  • Hay muchas más tecnologías desarrolladas para el paradigma de C/S.

Desventajas

  • La congestión del tráfico ha sido siempre un problema en el paradigma de C/S. Cuando una gran cantidad de clientes envían peticiones simultaneas al mismo servidor, puede ser que cause muchos problemas para éste (a mayor número de clientes, más problemas para el servidor). Al contrario, en las redes P2P como cada nodo en la red hace también de servidor, cuanto más nodos hay, mejor es el ancho de banda que se tiene.
  • El paradigma de C/S clásico no tiene la robustez de una red P2P. Cuando un servidor está caído, las peticiones de los clientes no pueden ser satisfechas. En la mayor parte de redes P2P, los recursos están generalmente distribuidos en varios nodos de la red. Aunque algunos salgan o abandonen la descarga; otros pueden todavía acabar de descargar consiguiendo datos del resto de los nodos en la red.
  • El software y el hardware de un servidor son generalmente muy determinantes: se necesita un buen "fierro" para que un servidor de soporte a una gran cantidad de clientes. 
  • El cliente no dispone de los recursos que puedan existir en el servidor y viceversa. Por ejemplo, una aplicación que ejecuta en el servidor no puede escribir en el disco local del cliente.

Otras taxonomías

O formas de categorizar las interfaces de usuario:
  • Orientadas a caracter: las consolas de configuración de routers, o las consolas de administración de herramientas como Maven o SVN, el intérprete de comandos de los sistemas operativos, el sistema de reserva de vuelos que trabaja con comandos específicos vs. interfaces gráficas: las que vamos a trabajar mayoritariamente a lo largo de la materia. ¿Qué características tienen las interfaces orientadas a caracter?
    • son menos intuitivas, hay que memorizar códigos, aprender comandos, pegar post-its sobre el monitor vs. guiarse por el menú
    • por esto se tarda más en aprender las operaciones que con las interfaces gráficas
    • una vez pasada la curva de aprendizaje los usuarios expertos trabajan mucho más velozmente que la modalidad gráfica
    • en ciertas herramientas hay acciones que sólo es posible realizar mediante la consola (interfaz orientada a caracter)
  • Interfaces de hardware y de software 
    • Con la aparición de nuevos dispositivos (tablets, netbooks, gps, smartphones, además de las tradicionales PCs y notebooks) se abre un juego nuevo: ¿cuánto afecta eso a la hora de pensar la presentación del lado del software? Dejamos la pregunta abierta...
    • En este último tiempo aparecieron las interfaces naturales de usuario (NUI) que sólo utilizan al cuerpo humano para ingresar información al sistema (las yemas de los dedos, los pies, o incluso los brazos, el movimiento de las pupilas reemplazan a los dispositivos de entrada como el teclado, mouse, lápiz óptico, etc). En todo caso tiene que más que ver con la parte de hardware, el output sigue siendo principalmente a través de un display gráfico por lo que todas las cuestiones de usabilidad siguen aplicando
  • Y como ya hablamos antes, diferenciamos 
    • Diseño gráfico de la interfaz: que la interfaz sea intuitiva, fácil de usar, consistente (que todas las acciones se hagan parecido o siguiendo el mismo criterio en todas las pantallas) 
    • Diseño de la aplicación: que las responsabilidades de los componentes estén correctamente distribuidas. Sin descuidar por de más el punto anterior, nos vamos a concentrar más en este punto a lo largo de la materia.

Para leer en casa

  • Un paper muy interesante sobre el diseño de interfaces de usuario

Conceptos que hay que repasar para la clase que viene

  • Template method
  • Listener/Observer
  • Composite
  • Strategy
  • Singleton