Archives

Categories


Links




Locations of visitors to this page


El maravilloso universo de la ingenería y desarrollo de software


Guía para la Reutilización de Software

Apr-202007

Continuando con la tercera entrega de los post relacionados a la reutilización de software, en esta ocasión compartiré algunos de los lineamientos que utilizamos para determinar la reutilización de algún elemento de software durante cada una de las fases del análisis, diseño, desarrollo y pruebas de una solución de software.

Requerimientos (Análisis)

Conjunto de lineamientos que aplicamos a la fase de requerimientos a fin de conseguir la mejor reutilización

  1. Recolectar requerimientos de tantos recursos como sea posible

    Mientras más requerimientos elaborados por recursos de la organización existan significan que la mayoría de necesidades de los nuevos usuarios están satisfechas, ya que se ha elaborado un punto de vista más general de ciertas necesidades y existen aspectos de soluciones que ya han sido revisados y comprobados, esta recolección de requerimientos generalmente es obtenido de un repositorio donde se encuentren almacenadas los diferentes requerimientos que se han elaborado para los diferentes soluciones o soportes de clientes ya existentes.

  2. Usar una sola notación y plantilla para todos los elementos de requerimientos

    Utilizar una sola notación bien conocida permite a los usuarios de diferentes proyectos entender el documento de requerimientos y sirve como punto en común para la revisión y reuniones de requerimientos.

    Se debe utilizar siempre las plantillas del proceso para el levantamiento de requerimientos, la falta de esta práctica generalmente ocasiona trabajo adicional.

  3. Hacer tantas revisiones de requerimientos como sea posible.

    Asegurar que el conjunto de requerimientos de todos los proyectos se realiza en una etapa temprana para facilitar la reutilización de requerimientos, además que las revisiones permiten evitar ambigüedades en los requerimientos y malos entendidos, ya que estos estarán validados.

  4. Analizar aplicaciones existentes

    Algunos requerimientos pueden resultar del estado actual de algunas aplicaciones. La ausencia u omisión de partes o problemáticas no descritas en los requerimientos actuales se pueden ver reflejadas en los nuevos requerimientos y crear nuevos requerimientos que no son obvios al principio. Mientras se analizan las aplicaciones existentes, es importante distinguir entre los requerimientos de la aplicación que son genéricos y los requerimientos que son una consecuencia de la estructura de la aplicación o implementación, estos últimos no deberían ser parte de los requerimientos reutilizables del componente o de la solución.

    Ejemplo:

    Requerimiento Original

    Se necesita que el sistema mantenga una sola instancia de Soporte Técnico sin importar los departamentos que la necesiten.

    Requerimiento Reutilizable

    El sistema implementa un patrón de "única instancia" para mantener una sola instancia de Soporte Técnico disponible.

  5. Agregar requerimientos funcionales, tales como escalabilidad, rendimiento y variabilidad a una plantilla reutilizable.

    Ejemplo:

    Requerimiento Original

    El sistema debe dar servicio a 100 clientes utilizando 10 conexiones a base de datos.

    El sistema deberá dar respuesta al usuario en menos 5 segundos

    Requerimiento Reutilizable

    Un sistema de tamaño A, debe dar servicio a K clientes, utilizando K/10 conexiones a base de datos.

    Un sistema de tamaño A, con una carga de datos de tamaño S en una red de Y Kbps con un porcentaje de demanda del T%, deberá dar respuesta en S/Y segundos en situaciones normales y (S*(T/4))/Y segundos en horas de mayor demanda.

Diseño

Algunos métodos y lineamientos mencionados son relacionados a cuestiones de Diseño Orientado a Objetos (OOD) (herencia por ejemplo) mientras otros son útiles también en procesos que no son OO.

  1. Hacer Partes Opcionales de Subsistemas Separados.

    Algunos nuevos usuarios pueden no requerir todas las funcionalidades del sistema. La fase de diseño debería permitirles adaptar sólo las partes que ellos necesitan. La creación de un subsistema separado de partes opcionales permite a los nuevos usuarios adaptar sólo los subsistemas que ellos necesitan.

  2. Hacer Componentes Fuertemente Conectados como un Subsistema.

    Es más fácil capturar la estructura del sistema, adaptarlo, y cambiar partes del sistema, cuando las interfaces de los subsistemas son pequeñas. Colocar clases fuertemente conectadas en subsistemas separados hace que sea muy difícil de sustituir algunas de sus implementaciones o estructurarlo sin la influencia de otros subsistemas.

  3. Hacer un solo Subsistema con clases que cambian con algún requerimiento.

    Cuando existe un conjunto de clases que cambiarán cuando algún requerimiento se cambie, es conveniente agruparlos para hacerlos un solo subsistema. Con el tiempo, el requerimiento se le puede añadir o cambiarse. Entonces un conjunto de cambios será aplicado al sistema y realizado solo a un conjunto ya definido. Es más fácil documentar los cambios necesarios y aplicarlos cuando todas las clases cambiadas son encapsuladas en un subsistema.

  4. Minimizar el Número de Subsistemas.

    Un número grande de subsistemas hace muy difícil de capturar y entender el sistema y por lo tanto muy difícil de adaptarse.

  5. Hacer la descomposición del Subsistema sólo como el último paso en la fase de Diseño.

    Sólo después de que todas las clases del sistema han sido totalmente definidas, la agregación de clase y las relaciones han sido identificadas y la jerarquía de clase es totalmente construida, es el tiempo para comenzar la descomposición en subsistemas. Sólo entonces las partes opcionales, el acoplamiento de clases y otras propiedades relacionadas con la Descomposición en Subsistemas son conocidos. Incluso aunque se intente comenzar el diseño por una división general del sistema en subsistemas, tal división prematura puede influir en la estructura total de las clases.

  6. Mantener la Jerarquía de Clase Simple y Estrecha.

    Mantener la jerarquía de clases amplia y dispersa refleja muy pocas abstracciones y poca funcionalidad compartida.

    Esto tiende a reflejar un diseño muy pobre. Los nuevos usuarios encontrarán difícil de seleccionar el diseño correcto para usar y las modificaciones al comportamiento de la clase forzarán cambios a un conjunto de clases y no sólo a una única clase común.

  7. Mantener Interfaces y Clases Pequeñas.

    Pequeñas clases e interfaces hacen mucho más fácil para el nuevo usuario entender las funcionalidades de los componentes y reutilizar estas clases e interfaces. Una interface muy complicada animará al nuevo usuario a crear su propia implementación simple.

  8. Mantener los Nombres de Función y Declaraciones Consistentes.

    Notaciones simples para funciones que aparecen en muchos sitios en el sistema, ayuda a los nuevos usuarios a entender la interfaz de la clase. Por ejemplo, muchas clases de colección pueden tener una función para insertar un nuevo elemento a la colección. En una lista esta función puede ser llamada "Add" y en una pila "Push" cada uno con una declaración y valor de retorno diferente. La mejor práctica podría ser usar el mismo nombre de función y declaración de modo que los nuevos usuarios sepan que para insertar un elemento a una colección, será siempre realizada con el método "Insert" que tiene una firma consistente.

  9. Cada Función deberá implementar Funcionalidad simple.

    Aunque los requerimientos puedan sugerir que dos tareas separadas nunca se realicen de manera separada (ej. crear un archivo "spool" en el disco que posteriormente es enviado a la impresora) algunos futuros nuevos usuarios pueden requerir usar sólo una de estas tareas (ej. sólo crear un archivo "spool" o enviar un archivo "spool" a la impresora y que no fue creado por el componente). Por lo tanto, es importante que cada función de clase sea responsable de solo una tarea simple.

  10. Identificar e Implementar Patrones de Diseño.

    En primera instancia la fuente de identificación de patrones lo proporcionan los requerimientos, pero no en todos los casos los patrones son detectados desde un principio, analizar el diseño y verificar si es posible implementar un patrón de diseño.

Codificación

Conjunto de lineamientos que aplicamos a la fase de construcción a fin de conseguir la mejor reutilización

  1. Especificar todas las partes que deberían ser sustituidas.

    En algunos casos, la reutilización es hecha utilizando componentes o servicios, ya sea por la reutilización de caja blanca (herencia, creación de sus instancias) o por parámetros. Todos los parámetros que deban ser obtenidos o cambios que deban ser hechos deben ser especificados. Es mejor si la reutilización es deshabilitada cuando estas acciones no son tomadas. Por ejemplo cuando se usa OO y el nuevo usuario debe suministrar algún parámetro P, definir una función virtual "getP" que obligará al nuevo usuario a implementar esa función a fin de usar el componente.

  2. Mantener Clases e Interfaces Pequeñas.

    Pequeñas clases e interfaces cortas hacen la reutilización más cómoda. Un nuevo usuario que debe aprender una interfaz de 300 funciones escribiría probablemente su propia implementación.

    Esto también aplica al número de parámetros de una función. Las funciones con muchos parámetros son difíciles de leer y difíciles de usar. Si algunas funciones necesitan muchos parámetros, lo mejor es crear una estructura que contenga todos los parámetros.

  3. Ocultar Datos Internos e Implementación.

    Exportar datos internos e implementación, puede causar los problemas siguientes:

    ■    Un nuevo usuario puede tratar de cambiar datos internos y causar errores inesperados.

    ■    Un nuevo usuario puede usar el componente en una manera que es inconveniente únicamente a la implementación actual, cambiando la implementación (sin cambios en la interfaz) causará errores.

    El componente o servicio debería exportar sólo los datos y/o esquemas que el nuevo usuario necesita y nada más.

  4. Usar Herramientas, Lenguajes y Notaciones Estándares.

    A fin de conseguir la mejor reutilización, el componente o servicio debe tener larga vida y ser saludable. La Utilización de ningún estándar o herramienta hace la migración del componente o servicio muy difícil.

    Además, las herramientas no estándar típicamente tienen un tiempo de vida mucho más corto que las herramientas y lenguajes estándares que tienen un soporte continuo.

  5. Componente Independiente.

    No utilizar o tratar de evitar alguna característica específica o poco común de un SO/Compilador/Base de Datos/Producto/Tecnología o cualquier otra característica no estándar o poco común de una herramienta.

    Usar una característica no estándar de cualquier herramienta de desarrollo, ata el componente o servicio a una herramienta, que al migrar a una nueva versión sea probable que ya no se le de soporte a esa característica poco común o no estándar. Por ejemplo, en la aplicación de base de datos, cada vendedor de base de datos por lo general suministra un lenguaje SQL que pone en práctica un SQL estándar. La utilización de un lenguaje que no sea SQL para consultar los datos hará que el componente no sea posible migrar a otras bases de datos.

  6. Usar Convenciones de Nomenclatura Estándares.

    Una convención de nomenclatura estándar hace mucho más fácil para entender el componente o servicio, hacer una mejor legibilidad de los nombres, variables, funciones, etc. y hacer el programa más claro y legible.

  7. Documentar tanto como sea posible.

    El mejor instrumento que un nuevo usuario tiene es la documentación del componente o servicio. Tanto la reutilización de caja negra donde los requerimientos, el diseño, la guía de programador y los documentos de manuales de usuario son requeridos. O la reutilización de caja blanca donde la documentación del código es muy importante.

  8. Usar Plantillas de Documentación Estándares.

    Es mejor usar un formato conocido para la documentación de código. La utilización de la documentación estándar ayuda al nuevo usuario a entender el componente o servicio y le ayuda a encontrar respuestas a sus preguntas rápidamente ya que la estructura de la documentación es conocida. La utilización de herramientas de documentación estándares como por ejemplo NDOC para .NET puede ayudar a la creación de la documentación estándar.

Pruebas

  1. Utilizar Pruebas de Exactitud en Componentes Pequeños e Importantes.

    Siempre que sea posible, según las consideraciones descritas anteriormente es aconsejable usar pruebas de exactitud de componentes o servicios reutilizables. Esto es verdad cuando el componente o servicio es pequeño y necesita una fiabilidad alta.

  2. Separar Casos de Pruebas para Requerimientos diferentes.

    Algunas unidades o requerimientos del sistema tienen casos de pruebas especiales. La organización de casos de pruebas por requerimientos ayuda al nuevo usuario a entender qué pruebas fueron hechas para el conjunto de requerimientos en el que él está interesado, los resultados y las pruebas involucradas deberían ser documentadas para completar las pruebas.

  3. Documentar las Pruebas.

    Todas las pruebas unitarias, de integración y de sistema que han sido ejecutadas y sus resultados deben ser documentadas y proporcionadas a los nuevos usuarios con la documentación del componente o servicio. Usando esta documentación el nuevo usuario puede estimar la calidad del producto y ejecutar pruebas adicionales para asegurar la exactitud del componente o servicio.

  4. Realizar Pruebas usando Datos Reales.

    Siempre que sea posible intentar realizar pruebas al componente o servicio utilizando datos reales de sistemas reales.

    Sólo de esta manera, se puede asegurar que el componente o servicio es probado en un ambiente de la vida real.

 

Como vimos existen innumerables ventajas para la reutilización de código, pero no todo es color de rosa, existen desventajas y costos que se originan de la utilización de elementos reutilizables, los cuales dependiendo del tipo de proyecto es necesario realizar una evaluación para determinar su factibilidad de ser incluidos en la solución; estos, los hablare en uno de mis siguientes post.

 
Posted by Efren Esteban Cruz Anguiano | 0 Comments | Bookmark with:        
Tags: Architecture

Links to this Post

Comments

Name:
URL:
Email:
Comments:

CAPTCHA Image Validation