¿Qué importa que algún capitán me ordene coger la escoba y barrer la cubierta?¿Quién no es un esclavo? Decídmelo.
Ismael, en Moby Dick

Archivos en la categoría Diseño

Diseño top-down, o cómo jugar al Golf

Llevo toda una vida pensando primero de arriba a abajo, de lo general a lo particular, es decir primero visualizo el problema, exploro la solución más óptima para elegir/construir las herramientas y componentes que mejor se adaptan, para finalmente retocar la solución de abajo a arriba ya que en todo este proceso puedes haber descubierto una solución más óptima, o mejores herramientas, mejorar o corregir fallos en el diseño y/o implementación…

Este proceso es como jugar un hoyo de golf.

Cuando te enfrentas a un hoyo, lo primero que haces es estudiarlo para encontrar el plan más óptimo según el hoyo, la meteorología, tu equipo, la variedad de golpes de tu repertorio y tu habilidad para ejecutarlos.

En un circuito profesional embocar de un golpe es improbable cuando no es imposible, así que el objetivo real del primer golpe es alcanzar primero un objetivo más genérico, el green, con una superficie de unos 500 metros cuadrados, en el menor número posible de golpes. Si el green está fuera de tu alcance actual, buscas una posición óptima, estable y segura en la calle que te permita acceder al green en el futuro más inmediato posible.

Si el green estuviera exageradamente fuera de alcance incluso con varios golpes, por ejemplo en un hoyo de 500 metros si sólo eres capaz de alcanzar 50 metros por golpe, no te molestes en trazar un gran plan, sólo en que tu actual golpe te deje en las mejores condiciones posibles para el próximo.

En cada golpe (iteración) te replanteas la situación, las condiciones meteorológicas, los obstáculos presentes y futuros (Riesgos potenciales), seleccionas una herramienta y cómo utilizarla, ejecutas el golpe y compruebas el resultado.

No siempre el resultado del golpe es el esperado: fallos en la estrategia o en la ejecución, obstáculos previsibles (fuera de límites, agua, bunker, árboles) e imprevisibles (ráfagas de viento, botes inesperados, animales…). Riesgos que se han materializado.

La desviación del objetivo suele traer consigo una serie de problemas e incluso penalizaciones: podemos alcanzar el lado no óptimo de la calle o el semi-rough que rodea la calle con la hierba más alta (menos potencia al golpe, menos precisión), que limita con el rough que es hierba sin cuidar o directamente suelo, algún obstáculo (árbol, bunker, agua) o salirnos del campo (fuera de límites) que nos obliga a volver a lanzar desde el mismo lugar y además nos penaliza.

En ocasiones sin embargo la suerte nos sonríe: un árbol, piedra o animal nos evita salirnos de calle o caer en un obstáculo. Es algo que raramente ocurre y es el peor veneno para los necios: cuanto peor es su situación más confían en esta suerte, porque les ocurrió en una ocasión y ahora esperan que les ocurra siempre.

Resulta vital saber cuándo avanzamos más frenando o incluso retrocediendo. Puede ser más seguro utilizar un hierro en lugar de una madera para sacrificar metros por precisión, o dejar un siguiente golpe más largo por el elevado riesgo del actual, o avanzar sólo unos metros pero asegurarnos de que volvemos a calle, incluso si eso significa retroceder. Es de cobardes retroceder siempre, pero de sabios acertar cuándo se debe retroceder.

Según nos acercamos cobra más importancia la precisión, hasta que finalmente alcanzas el objetivo deseado: el green. Pasamos de un objetivo general y difuso a un objetivo muy específico de 108 milímetros de diámetro. Si no te sales del green tarde o temprano embocarás, pero de nada sirve recorrer 500 metros en 2 ó 3 golpes si necesitas 7 para los 5 metros que te quedan: es el momento de la verdad, el que marca si tiramos por la borda todo el trabajo anterior.Leer su relieve es imprescindible para acertar, todo lo que no llega no entra, nunca salirse del green.

Et voilá, has embocado. La práctica lleva a la perfección, a elaborar mejores planes, a comprender mejor los riesgos, a decidir mejor, a ejecutar mejor.

En la vida real sería más loco y divertido jugar en ocasiones como si estuvieras jugando al croquet en el País de las Maravillas, con una Reina de Corazones cambiando las reglas del juego mientras ordena cortar cabezas, un Conejo Blanco que llega tarde a cambiar las banderas de los hoyos entre sí convirtiendo el hoyo que estás jugando en el número 5 en lugar del 2, Jardineros tapando el hoyo cuando estás preparando el putt mientras hacen otro agujero en otra parte del green, y un Naipe pasando el cortacésped cuando ejecutas el golpe.

En el software es casi siempre así, no hay margen para el aburrimiento :) .

PD, efectivamente, estoy planteándome volver al golf en el mejor campo que he conocido, en Zarapicos, Salamanca.

Introducción a UML

UML (Unified Modeling Language, Lenguaje Unificado de Modelado) es un lenguaje visual extensible de modelado de sistemas orientado a objetos, de propósito amplio y genérico estandarizado por el Object Management Group (OMG).

Nace del intento de unificar los lenguajes de modelado visuales más extendidos en 1994 (Booch, OMT…). En 1996 OMG lanzó una RFP (Request for Proposal) aceptado en 1997, marcando el nacimiento de UML. Hoy es un estándar de facto abierto en la industria del software.

UML concibe el mundo como colecciones de objetos que interactúan, por eso resulta idóneo para utilizarse en desarrollo de software con lenguajes orientados a objetos. Se utiliza para especificar o describir sistemas, artefactos, métodos y procesos durante todo el ciclo de vida del sistema sin importar la implementación ni el proceso de desarrollo, incorporando las mejores prácticas de modelado para que puedan ser fácilmente legibles por personas e implementarse por las herramientas software de modelado.

Existen dos aspectos en un modelo UML que no están completos el uno sin el otro.

  • Estructura estática, describe qué tipo de objetos conforman el sistema y cómo se relacionan.
  • Comportamiento dinámico, describe los ciclos de vida de estos objetos y cómo interactúan entre sí para entregar la funcionalidad requerida.

Un modelo UML tiene al menos dos dimensiones:

  • Textual, contiene las especificaciones de los diferentes elementos de modelado.
  • Gráfica, muestra gráficamente el modelo textual utilizando diagramas e iconos, son simplemente vistas o proyecciones visuales de ese plano posterior semántico. Pueden existir elementos elididos (si no se muestran gráficamente), incompletos (pueden faltar en ambas dimensiones) e incoherentes (contradicciones entre los elementos).

UML se compone de 3 Bloques de Construcción.

  • Elementos.
    • Estructurales. Son los nombres de un modelo UML, como una clase, interfaz, colaboración…
    • Comportamiento. Son los verbos de un modelo UML, como interacciones, actividades, máquinas de estado.
    • Agrupación. Paquetes que se utilizan para agrupar los elementos semánticamente en unidades cohesivas.
    • Anotación. Notas que se anexan al modelo para capturar información ad hoc.
  • Relaciones, unen a los elementos entre sí especificando cómo dos o más elementos se relacionan semánticamente.
    • Dependencia. El elemento origen depende del elemento destino y se puede ver afectado por cambios en éste.
    • Asociación. La descripción de un conjunto de vínculos entre objetos.
    • Agregación. El elemento destino es una parte del elemento origen.
    • Composición. Una forma de agregación más fuerte, más restringida.
    • Contención. El elemento origen contiene el elemento destino.
    • Generalización. El elemento origen es una especialización del elemento destino más general y se puede sustituir por éste.
    • Implementación. El elemento origen garantiza llevar a cabo el contrato especificado por el elemento destino.
  • Diagramas, nos muestran qué hará el sistema (diagramas a nivel de análisis) o cómo lo hará (diagramas a nivel de diseño).

UML utiliza 4 Mecanismos comunes para conseguir objetivos específicos:

  • Especificaciones, descripciones textuales de la semántica de un elemento.
  • Adornos, que se añaden a los elementos gráficos para hacer visibles aspectos de la especificación del elemento textual.
  • Divisiones comunes.
    • Clasificador/instancia (abstracción/especificación). Comparten icono pero las instancias tienen el nombre subrayado. UML proporciona 33 clasificadores (actor, clase, componente, interfaz, caso de uso…)
    • Interfaz/implementación. Separando lo que se hace de cómo se hace, los contratos ocultan la complejidad.
  • Mecanismos de extensión. UML no puede ser universal y satisfacer las necesidades presentes y futuras de todos los proyectos, por los que incorpora:
    • Restricciones, cadena de texto entre llaves que especifica cierta condición o regla sobre el elemento. UML define como una extensión estándar OCL (Object Constraint Language o Lenguaje de Restricción de Objetos).
    • Estereotipos, variaciones de un elemento de modelo existente con la misma forma pero con un propósito modificado, representado con el nombre del nuevo elemento entre cursores, <<…>>.
    • Valores etiquetados, son palabras claves que puede tener un valor anexado, al modo del valor de una propiedad.

Prototipado web: Axure RP

Herramienta para prototipado de aplicaciones web, aquí hablaré de la versión v5.6.

  • Herramienta de escritorio.
  • Página de inicio aquí.
  • Funcionalidades aquí.
    • Generación de documento de requisitos en Word a partir del modelo.
  • Software de pago, versión de 30 días de prueba aquí.

Carencias

  • Está pensado más para copiar y pegar que para reutilizar y parametrizar:
    • Falta de casos de uso globales comunes para toda la aplicación. Actualización: la versión 6 soporta casos globales y reutilizables.
    • Falta de evento onLoad para los paneles dinámicos para parametrizarse ellos mismos en lugar de tener que hacerlo en cada una de las páginas madre que les invocan.
    • Esto provoca que el desarrollo sea lento y tedioso, y los mantenimientos complejos y con altas posibilidades de bugs.
  • La calidad del código generado es mejorable
    • No puedes utilizar hojas de estilo CSS.
    • No puedes automatizar las pruebas del código generado, ya que los elementos se generan con un id que cambia en cada versión.
      • Dificulta aún más los mantenimientos y desarrollos incrementales.
    • No puedes partir del código generado para construir las plantillas de la aplicación. Actualización: la versión 6 parece que soporta plantillas, pero no sé si se comportan como las layout de struts tiles y modificando la plantilla modificas todas las páginas, o si sólo sirven de apoyo para el desarrollo.
  • La gestión de la memoria consumida es mejorable, cuando el prototipo empieza a crecer el manejo se vuelve exasperantemente lento.

Gestión de proveedores y partners – Diseño

Lo  primero que me llama la atención es lo difícil y costoso que es introducir cambios no previstos que afectan al diseño. Es decir, normalmente ya es costoso con un único equipo, pero poner de acuerdo a varios stakeholders en un cambio de diseño que les afecte aunque sea levemente parece una procesión de nazarenos de semana santa, todo son lloros y lamentos.

Los buenos diseñadores son sin duda el activo más importante de nuestra industria (y de cualquiera) en relación a costes y calidad, por la modularización y adaptabilidad de sus productos.

Una llamada de atención para los incondicionales de la refactorización (yo sólo soy fan): sí que hay funcionalidades que quedan mejor después de varias entregas y obtener el feedback del cliente, pero las que afectan notablemente al diseño son cuatro veces más costosas que hacerlo bien a la primera.

Una modificación estructural ya de por sí es cuatro veces más costosa que un diseño acertado a la primera porque…

  • primero por el coste de la primera implementación.
  • segundo porque cuesta más modificar que partir de cero.
  • tercero porque casi siempre queda peor (y más costoso y necesita más tiempo) que bien hecho desde el principio.
  • y cuarto el coste de la modificación en sí.

Con varios equipos involucrados se añade el poner de acuerdo a personas que no quieren estar de acuerdo, mientras lloran ganan tiempo y en ocasiones dinero. La teoría nos dice que deberíamos consensuar los cambios entre todos los implicados, pero la experiencia nos dice que tras un breve intento deberíamos imponer un diseño nosotros mismos (tras informarnos).

Algo tan sencillo como mover un enchufe de la pared de la cocina y la salida de humos de la campana, que incluso me considero capacitado para hacer yo mismo ya que la mayor dificultad es tener las herramientas y materiales necesarios, ha sido todo un logro poder acabar tal tarea por la disponibilidad de los equipos y los dimes y diretes entre constructores e instaladores de la cocina.

Por delante me queda estudiar la posibilidad de instalar paneles solares, o cambiar el plato de la ducha por baldosines, realmente me desanima las experiencias previas más leves. Parecen tareas para varias generaciones al lado de la anterior ;)

Imagen

Numeración de versiones de Software (v02.00.00)

Control de versiones es la gestión de los diversos cambios que se realizan sobre los elementos de algún producto o una configuración del mismo. Se aplica en informática sobre el código fuente y yo también lo utilizao para la documentación.

La numeración de las versiones de cada producto puede ser diferente, aunque la convencción más habiltual es utilizar 3 números, por ejemplo la versión v01.02.03. Me gusta que el número sea precedido por una “v” minúscula para dejar claro que es un número de versión y no confundirlo por ejemplo con una fecha, e incluyo los ceros por constumbre ya que me resulta más cómodo ver los números así para que cuando cambien de decena no se descuadren. Su significado suele ser:

  • El tercer dígito (build) representa correcciones de bugs o errores encontrados. También se suelen incluir cambios no funcionales (correciones ortográficas, cambios de color o tamaño de ventanas…) Es decir en el ejemplo se trata de la tercera entrega sobre la versión v01.02 en la que se reparan los bugs o errores detectados.
  • El segundo dígito (release) representa modificaciones funcionales, es decir se han añadido, eliminado o modificado funcionalidades al código. En el ejemplo se trata de la segunda entrega con modificaciones funcionales de la versión v01.
  • El primer dígito (versión propiamente dicho) representa cambios mayores en el diseño del código que impliquen cambios en el código de las aplicaciones que tengan dependencias con nuestro software (como pasar de Struts 1.3.8 a Struts 2.0, nuestro código debe cambiar).

La numeración suele comenzar en 0 para las versiones en producción, y el paso a la versión v01.00.00 suele indicar el arranque en producción. Así nuestro ejemplo se trata de una aplicación que está en producción y aún no ha sufrido cambios notables en su arquitectura.

En ocasiones se utiliza un cuarto dígito de versión (review) cuando el usuario/cliente/equipo de calidad debe validar una entrega devuelve la entrega. Así la versión v01.02.03.04 sería la cuarta entrega que hace el equipo de desarrollo al cliente para que se valide que se han solventado los bug, errores y modificaciones no funcionales objeto de la entrega v01.02.03.

También hay otras convenciones bastante utilizadas.

  • En algunos casos, las versiones cuyo segundo número sea par indica que son entregas al cliente e impar significa que son versiones de desarrollo.
  • En ocasiones en lugar de utilizar un cuarto dígito se utiliza una letra, por ejemplo v01.02.03c, a mí personalmente me gusta más.
  • De cara a los usuarios, hay gente que incluye alguna codificación para que se pueda identificar en qué fecha se liberó la versión, pero no ha tenido mucho éxito; resulta un problema cuando realizas dos entregas el mismo día.
  • Desde Windows rompiera totalmente esta tendencia con Windows 95, hay más equipos que “ponen un nombre” a sus cambios mayores de versiones. Eclipse es un ejemplo (Europa, Galileo, Ganymede…)

PD, este post es fruto de la revisión del original de 20080805.

Comenta