sábado, 29 de diciembre de 2012

Toma de Requisitos - Paso 6: Completar el prototipo

Hoy vamos a continuar explicando los pasos necesarios para una toma de requisitos, con el paso nº 6: completar el prototipo.
Esta entrada forma parte de una serie cuyo índice es el siguiente:
  1. Identificación de usuarios finales clave.
  2. Entrevista a dichos usuarios finales.
  3. Construcción de un prototipo basado en los resultados de las entrevistas. Es importante que el prototipo sea a la vez simple e interactivo.
  4. Presentación del prototipo a los usuarios finales, solicitando feedback.
  5. Desarrollar una guía de estilo que refleje el diseño/interfaz del prototipo.
  6. Completar y extender el prototipo hasta que demuestre funcionalmente todo el software.
  7. Utilizar el prototipo como la primera línea de base de los requisitos.
  8. Escribir una documentación de usuario detallada, basada en el prototipo anterior.
  9. Crear documentación de requisitos no funcionales para algoritmos, procesos, interfaces con otros sistemas hardware y software, etc.
Una vez hemos llegado a este punto, y tenemos una guía de estilo en condiciones, podremos pasar a completar el prototipo hasta hacerlo totalmente funcional.

Ojo, no estamos diciendo que el prototipo se acabe convirtiendo en la aplicación final. Esto ha sido ampliamente discutido en muchos foros, y tiene sus defensores (especialmente en el ámbito del software ágil) y sus detractores (especialmente desde el punto de vista de la ingeniería del software).

De esta forma, se consigue que los desarrolladores tengan una visión completa de lo que será el producto final. Hay dos visiones:
  • La visión del producto permite alinear el trabajo de los desarrolladores.
  • El prototipo detallado permite una visión mucho más detallada, facilitando a los desarrolladores el trabajo.
El prototipo, llegados a este punto, deberá ofrecer toda la funcionalidad del software, con al menos:
  • Todos los cuadros de diálogo, incluyendo los cuadros de diálogo estándar como Abrir, Cerrar, Imprimir, Guardar, etc.
  • Todas las pantallas de inserción de datos.
  • Todas las salidas de datos (pantallas, informes, listados...)
  • Todas las interacciones con el sistema operativo (ejemplo: importación y exportación al portapapeles).
  • Interacción con sistemas externos y otros productos de terceros.
El prototipo contendrá por tanto las principales interfaces:
  • Con el usuario
  • Con el sistema operativo
  • Con otros sistemas externos
Llegados a este punto, tendremos que hacer una línea base (no olvidemos la gestión de la configuración, que sea un prototipo-borrador no significa que debamos correr el riesgo de perderlo!!).

Tal y como establece Steve McConnell en su magnífico libro Software Project Survival Guide:

"No deberías usar un prototipo como la base de software real, así como no deberías usar un decorado de Hollywood como base para una casa de verdad".


El prototipo es un callejón sin salida, útil, pero un callejón sin salida. No ha habido una arquitectura, no está preparado para construir sobre él la aplicación final. La mayoría de autores recomiendan construir el prototipo en un entorno y en un lenguaje de programación que facilite el desarrollo rápido, pero que claramente no vaya a usarse en el desarrollo final. Por ejemplo, úsese Visual Basic o un lenguaje similar de alto nivel, cuando el desarrollo final vaya a ser en Java o C++ o C#. Esto evitará tentaciones más adelante.

jueves, 27 de diciembre de 2012

Ética e Ingeniería del Software

Fuente: http://www.asme.org/
Recientemente, en el blog de Javier Garzás he leído un post donde se propugna algo que llevo repitiendo hasta hartarme desde el primer post: que debemos comportarnos profesionalmente, de forma ética.

No somos charlatanes, patanes de feria que vendemos lo que nos convenga en función del beneficio que nos proporcione. En lugar de eso, damos al cliente lo que necesita en cada momento, maximizando su satisfacción y nuestro beneficio a largo plazo. Porque creemos en que la relación con nuestros clientes se cimenta en una confianza mutua, y ésta sólo puede realizarse a largo plazo.

Esta forma de pensamiento la he visto como eco en algún otro post. Me hace mucha gracia, que Javier afirma: "una metodología no es un equipo de fútbol, ni un partido político, ni una religión". Sin embargo, leo por doquier en la red continuas llamadas talibanistas a defender la religión del bloguero de turno:
  • Metodologías ágiles
  • Software libre
  • CMMI
  • Integración continua
  • <Pon aquí tu práctica/metodología/marco de trabajo>
El pensamiento que defiendo es similar al promulgado por Alistair Cockburn hace ya unos años:

"Estoy cansado de la gente que es de una escuela de pensamiento y que rechaza las ideas de otra escuela de pensamiento. Tengo hambre de gente que no le importe de donde vienen las ideas, que les importe sólo lo que significan y lo que producen. Así que se me ocurrió esto del “juramento de no lealtad”.
Esto significa el fin de afirmaciones como “eso no está bien – no es ágil / orientado a objetos / puro / etc.”, en vez de discutir sobre si la idea (ágil o tradicional o impura o lo que sea) funciona bien en las condiciones del momento."


Por desgracia, hay gente que incluso afirmando defender estas ideas, confiesa sus prejuicios y reticencias al respecto de ciertas formas de trabajar: "metodologías", "prácticas", "marcos de trabajo"...llamadlo como queráis.

Podemos estar convencidos de una cosa, pero no debemos defenderla si no es con argumentos probados, objetivos y no sólo cualitativos sino también cuantitativos. Por desgracia, esta forma de pensar encaja perfectamente en los que yo llamo "indecisos patológicos" o "charlatanes del depende". Sí, ya los conocéis. Me refiero a los que siempre contestan a todo con un "depende" (hasta aquí todo va bien), pero que cuando se les pide algo más de detalle o chicha en su discurso, podemos tener dos tipos de respuesta:
  • Verborrea coherente pero carente de fondo y forma, que al final no termina de dar ningún tipo de argumento veraz ni mucho menos objetivo hacia un lado u otro. Esta verborrea de político le viene muy bien a algunos individuos, que incluso les facilita la promoción profesional. Pero lástima de los clientes que acaben con ellos, y mucho peor: lástima de los que acaben en un proyecto dirigido por estos pseudo-profesionales.
  • Verborrea que sólo está orientada a alimentar el ego del que escucha. Son los llamados aduladores, los pelotas, que difícilmente terminan hablando del tema, sino que redirigen la conversación a un terreno menos objetivo y relacionado con el proyecto en cuestión.
Al querer escribir yo este post, me he encontrado con otro post bastante interesante. En él, su autor deriva la conversación a la ética informática, y al colegio profesional. Este autor, plantea la existencia de un tribunal de ética. Yo no sé lo que pensaréis pero empiezo a estar harto de tribunales, comisiones, cortes, comités de supervisión, equipos de trabajo, etc, etc. Y estoy harto de apelar siempre a un "ser superior" que nos proteja y defienda.

Es muy fácil: lo único que puede definir el comportamiento ético o no en un proyecto es la documentación. Los criterios objetivos, y la forma en que se basan y defienden, es lo único que puede usarse como valor ético en un proyecto. Pero claro, decir esto cuando la moda es ir en contra de la documentación, ser ágil, y entregar todo de forma rápida (y sin documentación), es poco menos que escupir al viento. Pero no deja de ser cierto. No es posible verificar la ética en un proyecto sin contrastar el contrato, con las decisiones tomadas (y las decisiones, o se documentan...o se pierden). Y es así en todas las profesiones.

Después de todo, en una profesión en la que no hay estándares cerrados, en los que no hay normas internacionales que establezcan la forma correcta de trabajar, todo vale. No podemos a la vez defender que hacer software es un arte, y al mismo tiempo querer crear Colegios, Comisiones éticas que verifiquen el buen hacer...respecto a qué?

En fin...excelentes Alistair Cockburn en su comentario, y Javier Garzás y Jorge Ubeda en sus respectivos posts. Espero que esta pequeña reflexión mía haya podido aportar algo.

domingo, 23 de diciembre de 2012

Cuando la culpa no es del usuario II

Recientemente he conocido a Martin, y me ha comentado que le ha gustado mi post "La culpa no es del usuario".

Martin es un profesional en un sector difícil y cada día más competitivo. Conoce, aunque no es profesional del sector, la tecnología en sus diversos ámbitos. Le tocó sufrir la desidia y dejadez de las empresas de telefonía móvil en España, que muchas veces no se molestan en tener actualizado su software.

Recientemente, Martin quiso probar la disponibilidad y cobertura en su domicilio de una conocida empresa operadora de ADSL. Para saber si había cobertura, tenía que rellenar un formulario. En el mismo, se le solicitaba su dirección y número de teléfono. Nada fuera de lo normal hasta ahí. Sin embargo, cuál no sería su sorpresa al comprobar que no funcionaba. La respuesta fue que su número de teléfono estaba equivocado. Martin lo comprobó una y otra vez. Pero la respuesta fue la misma.

El software estaba equivocado, no su número de teléfono. En España, los teléfonos fijos empezaban en "9". Sin embargo, algunas provincias, han ampliado su capacidad utilizando números que empiezan en "8". ¿Resultado? Aunque ya hace bastante tiempo que existen números de teléfono que empiezan en "8", el proveedor de ADSL seguía con un software obsoleto, incapaz de adaptarse a esta realidad.

¿Y ahora qué? Pues este conocido operador de ADSL ha perdido a un cliente. Ha hecho perder el tiempo a este señor (y seguramente a muchos más).

Como he dicho ya muchas veces en este blog, lo importante, la base de todo desarrollo son los requisitos. Y este caso es un claro ejemplo de requisitos mal tomados y mal implementados.

Además, fallaron las pruebas. No se definieron correctamente pruebas que recogieran las diversas posibilidades. Los casos de prueba no contemplaron las posibilidades.

Al final, por muy ágiles que seamos, por muy rápidos que queramos ser al poner un producto al mercado, no puede ser despreciando un mínimo de disciplina en estas áreas tan necesarias: requisitos y pruebas.

Gracias Martin por dejarme este comentario tan real como aleccionador.

sábado, 15 de diciembre de 2012

Enfermedades del software: Singletonitis

Patrón Singleton en notación UML
De nuevo, una enfermedad del software que a más de uno le va a sorprender. Y sin embargo es muy pero que muy vieja. Al final de esta entrada tenéis unos cuantos ejemplos de fuentes que he utilizado y que me han recordado lo peligroso que es usar patrones sin conocimiento, pero especialmente, el más simple de todos: el patrón Singleton.

¿En qué consiste el patrón Singleton?

Este patrón es el más sencillo, y también uno de los más conocidos y utilizados. Básicamente, su propósito es asegurar que sólo exista una instancia de una clase dada.

Singletonitis, una definición

Bien, dada la definición anterior, el anti-patrón Singleton ha recibido el nombre de "singletonitis": desorden transitorio del programador, que le lleva al abuso del patrón Singleton. Algunos autores van más allá, y definen claramente al patrón Singleton como un verdadero anti-patrón (es más causa de problemas, que solución de ninguno: o como se suele decir, pan para hoy, y hambre para mañana).

En el libro "Refactoring to Patterns", el autor Joshua Kerievsky presenta el término Singletonitis, refiriéndose literalmente a "la adicción al patrón Singleton". Este autor, propone un tipo de refactorización que llama "Inline Singleton", cuyo objetivo es eliminar los Singletons innecesarios en una aplicación.

Hay muchos problemas con el patrón singleton. Demasiados. Algunos de ellos:
  • Crea una alta dependencia en el código. Un alto acoplamiento que es fuente de problemas
  • Crea problemas con las pruebas y su automatización, especialmente por la alta dependencia del código al tratar de hacer pruebas unitarias.
  • Problemas con el multi-hilo y concurrencia.
  • Alta probabilidad de crear spaguetti-code, difícil de leer e incluso de debuguear, por acumulación de uno o varios de los anteriores.
  • Problemas de reusabilidad. Lo mismo, por acumulación de uno o varios de los anteriores.
En uno de los artículos que he revisado, el autor (Taskinoor Hasan ), ha tratado de hacer una aproximación seria, tratando de dar una solución lógica a los diversos problemas que el autor va detectando en su inocente implementación del patrón Singleton. De tan serio que es el artículo, y la acumulación sucesiva de problemas que presenta, acaba siendo hasta ridículo y divertido.

Del tema de la concurrencia y problemática con los entornos multi-hilo, hay varios artículos que presentan estrategias más o menos eficaces en función de la situación, lo que complica la resolución del problema. Y es que hay que ver lo bonito que es todo cuando en nuestra ignorancia, planteamos un sistema con Singletons creyendo que éstos van a ser instancias mono-uso. Con el paso del tiempo, la experiencia (y la dura realidad), nos van enseñando que al ver las cosas desde un nivel superior, o al tratar de reutilizar componentes, nuestro pequeño patrón Singleton es una fuente de problemas. Además, esos problemas al haber tanto acoplamiento en el código y dificultad de testeo, son complicados de detectar y resolver.

Frases como "esto nunca se va a usar en multi-hilo", tan categóricas, deberían ir siempre acompañadas de un "zas, en toda la boca".

Es duro ver cómo la falta de previsión y el abuso de patrones (patronitis), hace que las cosas se usen fuera de contexto y acaben haciendo todo menos aquello para lo que fueron diseñadas.

Solución: ¿vacuna o erradicación?

No son pocos los autores que defienden la total prevención mediante la erradicación de la causa de la Singletonitis, evitando dicho patrón.
Otros, elaboran complejísimas estrategias para detectar problemas, incompatibilidades, etc. Incluso existe una estrategia de validación dentro del patrón llamada "Double Check Locking", diseñada para evitar que en el caso de multi-hilo, haya problemas derivados de los bloqueos necesarios dentro del patrón.
Yo propongo algo que varios de los autores defienden, y es el uso de otro patrón (que por supuesto tendrá su enfermedad asociada por abuso), y es el de IoC (Inversion of Control).

¿Y tú? ¿Ya has sufrido tu Singletonitis?...

Fuentes:

http://taskinoor.wordpress.com/2011/04/18/singleton_multithreaded/
http://www.antonioshome.net/blog/2006/20060906-1.php
http://pragmaticintegration.blogspot.com.es/2006/02/singletonitis.html
http://www.theserverside.com/discussions/thread.tss?thread_id=42116
http://www.gamedev.net/blog/32/entry-510687-why-are-you-infected-with-singletonitis/
http://msdn.microsoft.com/es-es/library/bb972272.aspx
http://www.teatromagico.net/foro/viewtopic.php?f=4&t=13513&p=454983
Gamma E., Helm, R., Johnson, R., Vlissides J.: Design Patterns: Elements of Reusable Object Oriented Software, Addison Wesley, 1995.
Kerievsky, Joshua: Refactoring to Patterns, Addison-Wesley, 2004.
http://weblogs.asp.net/sfeldman/archive/2008/10/22/singletonitis.aspx

jueves, 13 de diciembre de 2012

La culpa no es del usuario

Hoy vamos a ver quién tiene la culpa de los fallos del software.
Me acabo de encontrar una referencia a mi antigua entrada "Cuando la culpa es del usuario", en la que yo bromeaba sobre quién tiene la culpa de los fallos en el mundo del software. Yo pensaba contestar o comentar en aquél blog, pero al final, había que registrarse y he desistido. Sin embargo, al ver los argumentos a favor y en contra, he pensado que hay que darle otra oportunidad a mi antigua entrada, y recuperarla, esta vez de forma algo más seria.

¿Quién tiene la culpa de los fallos del software?

Vamos a verlo con un ejemplo. Supongamos que hacemos una casa: planos, diseño, ejecución de la obra...todo. Y el usuario entra en la casa a vivir. Hemos construido la casa en base a las funcionalidades habituales: comer, desayunar, ir a dormir, ir al baño, entradas de luz, etc. Además, hemos cumplido las normativas existentes: seguridad, anchura y altura de puertas y ventanas, acceso de luz, aislamiento térmico, etc.

Supongamos que el usuario hace algo imprevisto como intentar salir por la ventana (y es un 8º piso). Si se muere, ¿está claro que es su culpa, no? Pero si le dejamos abierta la puerta al cuarto de alta tensión y no ponemos ninguna medida de seguridad...si se electrocuta y muere...quizás la culpa SEA NUESTRA.

Ahora supongamos que hace otras cosas como entrar por el garage en vez de la puerta de entrada, o tiene la absurda (o no tan absurda?) idea de comprar un sofá o una cama y éstos no caben por la puerta. Puede también querer mirar por la ventana, y encontrarse conque ésta da a la pared del siguiente edificio al que el nuestro se encuentra pegado (vamos, que sólo va a ver y tocar pared). ¿Quién tiene la culpa de esto?

Volvamos al mundo del software y veamos unos pocos casos más tecnológicos:
  • El usuario entra en una parte no permitida del sistema. No podemos impedir que alguien obtenga una contraseña. Hasta ahí es cierto. Pero es nuestra responsabilidad como desarrolladores de software, que no sea posible acceder a partes del sistema restringidas, con una clave no autorizada. Esto me hace mucha gracia, porque tenemos la chulería de exigir que Windows sea super-mega-seguro...pero luego hacemos aplicaciones con más agujeros que un colador. Y entendemos que necesitamos un tiempo razonable para probar y corregir nuestros agujeros de seguridad (somos humanos, verdad?), pero no tenemos la misma tolerancia cuando en vez de desarrolladores, somos usuarios. Exigimos que el programa o sistema operativo que falla, se corrija DE INMEDIATO (los que lo programan no deben de ser humanos, sino robots). Y gratis. Y....vamos, que está claro que sabemos pedir...pero no dar. Exigimos derechos desproporcionados a los deberes que asumimos.
  • El usuario juega con el sistema. Pues que juegue. Es el usuario. ¿Que lo rompe o cuelga haciendo alguna tarea prohibida? Para eso están los logs. ¿Que mete datos estúpidos o incorrectos? Para eso están los logs y el sentido común. Por supuesto, también están las validaciones de datos. Si permitimos "XXX" como fecha de nacimiento, probablemente la función de cálculo de Edad fallará.
  • El usuario tiene que sacar su trabajo, que no es precisamente saber de la tecnología interna del programa. No tiene porqué saber si es puro Java, o JQuery...o lo que sea.
En fin, habría muchos más ejemplos que ahora mismo no tengo tiempo de abarcar. Pero sí me gustaría comentaros un caso real de un colega de profesión ha tenido, y que creo que va a ser representativo.

Caso real.

  • Se trata de una aplicación web.
  • En uno de los cambios de especificación, se añade soporte para iPad.
  • La aplicación se prueba, y funciona correctamente en varios navegadores, tanto en Windows como en dispositivos iPad (hasta en Android!)
  • Cuando llega el usuario, descubre que cierta funcionalidad, sólo está disponible con ratón: al pasar el ratón por encima de los elementos de la página, aparece una información específica de cada elemento. Esto, se introdujo por diseño para disminuir la información de pantalla. Y está genial. Pero un iPad no tiene ratón.
  • Resultado: enfado del usuario y rediseño de la aplicación.
  • ¿Quién tuvo la culpa?

Conclusiones:

Para acabar, resumamos las conclusiones de lo que hemos visto, y de lo que la experiencia me ha hecho ver en todos (y son muchos) estos años:
  • El usuario no tiene culpa alguna de los errores que se producen.
  • Es nuestra responsabilidad poner "paredes" y "puertas y ventanas" a la aplicación para permitir el acceso o no a las funcionalidades.
  • Es nuestra responsabilidad cumplir las normas y estándares existentes, así como adaptarlos no sólo al tipo de usuario, sino al entorno (hardware y sistemas software con los que interactúe).
  • Es nuestra responsabilidad identificar posibles interacciones del producto con otros productos, y ponerlo  como funcionalidades (si funciona) o restricciones (si no funciona).
  • Es nuestra responsabilidad probar. Y probar todo, o asumir los riesgos de lo que no se prueba. Leía recientemente un post donde un compañero de profesión decía que no se puede cubrir todo con las pruebas. Y es cierto. Pero eso no significa que nos tapemos los ojos e ignoremos los riesgos.
  • Automatizar es la clave: debemos hacer pruebas unitarias, y automatizar también las funcionales en la medida de lo posible. En el caso real que se ha mencionado, el problema no era del usuario, era de que no se hicieron todas las pruebas en todos los entornos. Si probar todo en tu PC cuesta 2 días...añadir un nuevo entorno (iPad), costará el doble (bueno, es una primera estimación).

lunes, 10 de diciembre de 2012

Toma de requisitos - Paso 5: Crear una guía de estilo

Hoy vamos a ver el paso 5º de la guía sobre toma de requisitos.
Esta entrada forma parte de una serie cuyo índice es el siguiente:
  1. Identificación de usuarios finales clave.
  2. Entrevista a dichos usuarios finales.
  3. Construcción de un prototipo basado en los resultados de las entrevistas. Es importante que el prototipo sea a la vez simple e interactivo.
  4. Presentación del prototipo a los usuarios finales, solicitando feedback.
  5. Desarrollar una guía de estilo que refleje el diseño/interfaz del prototipo.
  6. Completar y extender el prototipo hasta que demuestre funcionalmente todo el software.
  7. Utilizar el prototipo como la primera línea de base de los requisitos.
  8. Escribir una documentación de usuario detallada, basada en el prototipo anterior.
  9. Crear documentación de requisitos no funcionales para algoritmos, procesos, interfaces con otros sistemas hardware y software, etc.
Los usuarios han aceptado y validado el prototipo (sí, eso fue el Paso 4 anterior). Así que ahora, los programadores deberían crear una guía de estilo: un pequeño manual o guía que identifique los estándares de estilo a seguir durante el inminente desarrollo software.

A ver, que esto no es una metodología: no hacen falta 200 páginas. Ni 20. Seguramente, con un par de páginas será suficiente. Habrá que añadir:
  • Estilos visuales
  • Imágenes con las pantallas más representativas (los 2 o 3 tipos de pantallas o cuadros de diálogo a mostrar).
  • Ubicaciones de los botones, incluyendo los más habituales (Aceptar, Cancelar, etc).
  • Estilos visuales: efectos, colores, tipos de letra.
  • Mensajes de texto a mostrar. Se trata de buscar una terminología común, que todos los conceptos tengan un nombre único, usado de forma consistente en todas las pantallas, y sea un nombre familiar en el contexto del negocio del cliente.
  • Estándares existentes a los cuales nos vamos a adherir sobre todo a nivel de usabilidad y accesibilidad.

Por supuesto, tras completarla, deberá revisarse y hacer una línea base (ponerla bajo control de cambios). Para esto no hace falta nada del otro mundo: un subversión o un repositorio similar bastarán.

Los estilos visuales, cuanto antes sean definidos, más fácilmente lograrán que haya consistencia en la interfaz de usuario. Después de todo, los requisitos cambiarán. Pero el aspecto visual ,es un buen sitio por el que empezar como base.

Para finalizar, van algunos estándares o normas relacionadas con los interfaces:
  • ISO/IEC 9126: evaluación de productos software.
  • ISO 9241: requisitos ergonómicos para trabajar con terminales de presentación visual (VDT)
  • ISO/IEC 10741: interacción de diálogos.
  • ISO/IEC 11581: símbolos y funciones de los iconos.
  • ISO 11064: diseño ergonómico de centros de control.
  • ISO 13406: requisitos ergonómicos para trabajar con presentaciones visuales basadas en paneles planos.
  • ISO 13407: procesos de diseño centrados en la persona para sistemas interactivos.
  • Guías de estilo para la web: IBM, W3C