InterfazHumanizada
Escrito por Martin Fowler
Traducido por Carmen Vidal
Revisado por Jorge Ferrer
Dando vueltas durante un rato al alboroto acerca de Ruby, he encontrado por casualidad el término 'la interfaz humanizada'. Éste describe parte de la actitud rubística al escribir la interfaz de la clase y también establece un contraste interesante entre dos escuelas de pensamiento en el diseño de APIs (el otro es el InterfazMinimalista).
La esencia de la interfaz humanizada es averiguar qué quiere hacer la gente y diseñar la interfaz de modo que sea realmente fácil hacer el caso común.
El contraste obvio con una interfaz minimalista es que las interfaces humanizadas tienden a ser mucho mayores, y de hecho los diseñadores de interfaces humanizadas no se preocupan demasiado de si la interfaz es grande. Esto no quiere decir que las clases con interfaces humanizadas tienen que ser más grandes en términos de implementación. La funcionalidad fundamental de las dos es a menudo bastante similar.
Una forma buena de ver la diferencia entre interfaces humanizadas y minimalistas es comparar el componente lista en Java y Ruby. Java tiene una interfaz (java.util.List) que declara 25 instancias de métodos. Ruby tiene una clase Array (que es una lista, no un array) que tiene 78 métodos. La diferencia en tamaño es una pista de que hay un estilo diferente. Ambos componentes ofrecen el mismo servicio básico, pero el array de Ruby incluye mucha funcionalidad adicional. Esta funcionalidad es una serie de pequeñas cosas que también pueden ser construidas con una interfaz minimalista de Java.
Veamos un pequeño ejemplo que nos ayuda a mostrar la diferencia: obtener el último artículo de la lista. Para hacer esto en Java tenemos:
aList.get(aList.size -1)
en Ruby sería:
anArray.last
De hecho, es incluso más llamativo que esto: El Array de Ruby tiene un étodo "first" también, de modo que en lugar de usar "anArray[0]" se puede sar "anArray.first". ay ejemplos de funcionalidades más complejas también. El Array en Ruby tiene un mtodo "flatten" ( aplanar) que toma arrays anidados y los pasa a un sólo nivel.
irb> [1,2,[3,4,[5,6],7],8].flatten
=> [1, 2, 3, 4, 5, 6, 7, 8]
La diferencia aquí está en la funcionalidad, métodos tan simples como "last" o tan complejos como "flatten", pueden ser escritos por los propios clientes sin aumentar el tamaño de la clase lista. Los Minimalistas tienden a centrarse en el conjunto mínimo de métodos necesarios para soportar estos comportamientos, los diseñasores de interfaces humanizadas tratan de añadir los métodos que son necesearios.
Esto nos obliga a las siguiente pregunta: "¿ Cuál es la base para decidir que debería ser añadido a una interfaz humanizada? " Si se añade todo lo que alguien podría querer se consigue una clase muy compleja. Los diseñadores de interfaz humanizada tratan de identificar los usos más comunes de una clase, y diseñan la interfaz para facilitar estos usos.
Este principio no sólo determina los métodos que se añaden, sino que también afecta a cómo nombrarlos. En RubyConf, Tanaka Akira indicó el valor de elegir nombres cortos para métodos comunes. Ya que estos son usados más a menudo te familiarizas con ellos - es fácil recordar nombres breves si se usan mucho. También es más útil, ya que ahorra al escribirlos y al leeros. Un ejemplo de esto es el método "parse" de la clase "DateTime" que hace una parseado por defecto de formatos de fecha comunes y "strptime", más flexible, que puede tomar cualquier formato, pero que se usa menos a menudo.
Otra consecuencia interesante de la filosofía de interfaz humanizada de Ruby son los nombres de métodos alias. Cuando quiera la longitud de una lista, ¿ debería usar "length" o "size"? Algunas librerías usan uno, otras el otro. El "Array" de Ruby tiene ambos, marcados como alias de modo que el uno o el otro nombre llaman al mismo código. La opinión de los rubistas es que es más fácil que la biblioteca tenga ambos que pedir a los usuarios recordar cuál es.
Se pueden tener largas y pesadas discusiones sobre qué estilo de diseño de interfaz es mejor. Aquí trataré de resumir los argumentos a favor de la interfaz humanizada (mirar InterfazMinimalista para el otro caso).
La mayor parte de la fuerza de un objeto está en su comportamiento, no en sus datos. Si sólo se trata de proporcionar el minimalista, se termina con múltiples clientes que duplican el código para casos comunes. En casos como "flatten" se termina con un conjunto de gente que escribe sus propias funciones repetidamente. No es difícil, pero ¿ por qué deberían ellos molestarse cuándo no se trata de un caso raro?.
Incluso para casos simples como "last", los lectores tienen que aprender un idiom. ¿Por qué tienen ellos que ver algo indirecto, cuando un método simple lo hace directamente? El software bueno piensa en los usuarios primero y les hace la vida fácil. Los interfaces humanizadas siguen este principio.
Los interfaces humanizadas hacen más trabajo de modo que los clientes no tengan que hacerlo. En particular, los usuarios humanos del API necesitan cosas de modo que sus tareas comunes sean fáciles de hacer - tanto para leer como para escribir.
Hay argumentos buenos a ambos lados. Personalmente me inclino al acercamiento de Interfaz humanizada, aunque yo realmente piense que es más difícil.
Continuación
Este artículo ha causado controverisa, lo que ha generado alguna discusión interesante y útil. Elliotte Harold atrajo mucha atención por una crítica corta pero robusta del acercamiento humananizado. James Robertson contestó (asegúrese de ver los comentarios), como hizo Cees de Groot, Antonio Vieiro, David Hoefler, James Higgs, Peter Williams, Cedric Beust, John D. Mitchell, y Sutart Roebuck. Elliotte contestó otra vez con un ejemplo de mandos a distancia y promete más. Hasta ahora la discusión ha estado bien y ha evitado demasiada invectiva.
Hay más también, no he indicado todos ellos y sólo he puesto aquellos que pienso que añaden algo interesante al debate y evitan la invectiva. Hay una tendencia a centrarse en el ejemplo (Array de Ruby frente a List de Java) más que en la idea subyacentes, pero esto es normal. Hay un número de direcciones interesantes en las que avanza la discusión, si tengo oportunidad trataré de desarrollar uno o dos de ellos.


Interfaz humanizado ¿ va en contra de KISS o YAGNI?
Éste artículo de Martin Fowler me ha parecido bastante interesante. Como se puede ver en la continuación introducida por Martin Fowler, ha generado bastante discusión. No he leído todos los comentarios pero en varios se dice que la idea de interfaz humanizado va en contra de YAGNI o KISS.
En mi opinión no es así. En el caso de estas librerías que van a ser usadas por un conjunto de gente que no las ha desarrollado, KISS es justo introducir los métodos más comunmente usados, para evitar que se tenga que repetir código por los distintos usuarios.
¿ cuál es vuestra opinión?
Opino como tu, realmente la
Opino como tu, realmente la idea de humanizado no va en contra de Yagni.
Una de las ideas que me ha venido a la cabeza cuando he leido este articulo es que muchas veces tratamos de ser demasiado academicos, y al final la experiencia saca nuestro lado pragmatico, que suele ser el mas eficiente. ¿No lo creeis asi? Este para mi es un claro caso. Las interfaces humanizadas son al final una visión mucho mas pragmatica de la programación.
No te digo ni una cosa ni la otra
Bueno, la verdad es que yo he probado ambos estilos en diferentes proyectos.
Lo cierto es que una interfaz humanizada se puede volver compleja de mantener como no vayas con cuidado. Yo en alguna ocasión he tenido que delegar la mitad de los métodos de una clase humanizada a nuevas clases porque la susodicha crecía y crecía sin parar, y como consecuencia se me hacía realmente díficil saber donde estaba cada cosa o cada porción de código relacionada.
Sin duda la gran ventaja de estas interfaces es que el cliente o el desarrollador sólo tiene que mirar en un único sitio para conocer lo que hay disponible.
Por otra parte, justamente por eso me encuentro más a gusto con las interfaces simples. Sin embargo, el problema con éstas es que sin haber leído todas las discusiones que menciona Cármen, yo considero que la interfaz simple en algunas ocasiones puede ir contra el principio KISS, exáctamente al contrario de lo que pareciera en un principio. ¿Cómo? Pues bueno, si quieres modelar una estructura compleja, y decides crear partes demasiado simples, al final te encontrarás que toda la estructura intermedia se convierte en un enjambre de relaciones a menudo innecesarias que aumentan la complejidad del sistema => Seguir un principio KISS a un nivel bajo no implica que el resultado sea KISS.
Aún así, y utilizando los ejemplos de Martin Fowler, a mi me gusta el estilo java: java.util.List + Collections ( sería un mejor ejemplo si java tuviese las commons-collections :-D), es decir, clase con la funcionalidad básica, y clases de ayuda con todas las utilidades que se nos ocurran para esa clase. Me parece una manera más elegante de separar comportamiento básico y estructural de funcionalidades adicionales. Otro ejemplo, String vs StringUtils, creo que se entiende lo que quiero decir, ¿no?
Martín
El lenguaje importa
Y mucho. No es lo mismo programar en Java que en Ruby (o Smalltalk). Mi experiencia en Ruby es mínima, pero tengo entendido que es posible declarar métodos de una clase fuera de esta, en extensiones. La filosofía de Ruby es distinta de la de Java.
Esta es una de esas discusiones (junto con la aplicación práctica de TDD) sobre metodologías ágiles que me refuerzan en la idea de que el lenguaje de programación (y el entorno de ejecución) que se utiliza en la aplicación de una determinada metodología es vital. El lenguaje condiciona y mucho la forma de programar.
A Martin Fowler le gusta tomar prestadas ideas del mundo de Smalltalk y trasladarlas al mundo Java, pero no siempre afortunadamente.