# Diseño de software

El diseño de software es el proceso por el que un agente crea una especificación de un artefacto de software, pensado para cumplir unos objetivos, utilizando un conjunto de componentes primitivos y sujeto a restricciones. El diseño de software se puede referir a "toda la actividad implicada en conceptualizar, enmarcar, implementar, poner en funcionamiento y, finalmente, modificar sistemas complejos" o "la actividad que sigue a la especificación de requisitos y precede a la programación, como en un proceso de ingeniería de software estilizado".
El diseño de software normalmente implica un problema a solucionar planeando una solución de software. Esto incluye un componente de bajo nivel que incluye un diseño de algoritmos y un alto nivel que incluye un diseño de la arquitectura del software.

## Visión general

El diseño de software es el proceso de visionado y definición de soluciones software a uno o más conjuntos de problemas. Uno de los componentes principales del diseño de software es la especificación de requisitos del software (ERS). Se trata de una parte del proceso de desarrollo de software que enumera especificaciones empleadas en ingeniería de software. Si el software está "automatizado" o centrado en el usuario, el diseño de software puede implicar también el diseño de experiencia de usuario que utiliza un storyboard o guion gráfico para ayudar determinar esas especificaciones. Si el software es completamente automatizado (es decir, sin usuario o interfaz de usuario), un diseño de software puede ser tan sencillo como un diagrama de flujo o un texto describiendo una secuencia planeada de acontecimientos. También hay métodos semiestándares como el Lenguaje Unificado de Modelado (UML) y conceptos fundamentales de modelado. En cualquier caso, normalmente alguna documentación del plan resulta como producto del diseño. Además, un diseño de software puede ser independiente de la plataforma o específico de la plataforma, dependiendo de la disponibilidad de la tecnología utilizada para el diseño.
La diferencia principal entre análisis y el diseño de software es que la producción de un análisis de software se compone de problemas más pequeños para solucionar. Además, el análisis no tendría que ser diseñado de manera muy distinta por miembros de equipo diferente. En contraste, el diseño se enfoca a capacidades y, por tanto, múltiples diseños existen y existirán para el mismo problema. Según el entorno, el diseño también varía en función de si se está creando a partir de frameworks fiables o implementando con patrones de diseño adecuados. Ejemplos de diseño incluyen sistemas de operaciones, páginas web, dispositivos móviles o incluso el nuevo paradigma de computación en la nube.
El diseño de software es un proceso y un modelo. El proceso de diseño es una secuencia de pasos que habilita al diseñador para describir todos los aspectos del software a construir. La habilidad creativa, la experiencia, el sentido de qué hace a un software que sea bueno y el compromiso con la calidad son ejemplos de factores críticos para el éxito de un diseño competente. Es importante tener en cuenta aun así que el proceso de diseño no es siempre un procedimiento sencillo; el modelo de diseño puede ser comparado con los planos de una casa para un arquitecto. Se empieza representando la totalidad de la cosa que se va a construir (p. ej., un renderizado tridimensional de la casa); la cosa se va refinando lentamente para servir como guía a la hora de construir cada detalle (p. ej., la parte de fontanería). Del mismo modo, el modelo de diseño que se crea para el software proporciona una variedad de visiones distintas del software. Los principios básicos de diseño ayudan al ingeniero de software a navegar por el proceso de diseño. Davis sugiere un conjunto de principios de diseño de software que han sido adaptados y extendidos en la siguiente lista:
* El proceso de diseño no tendría que sufrir "visión de túnel." Un buen diseñador tendría que considerar enfoques alternativos, juzgando cada uno basándose en los requisitos del problema, en los recursos disponibles para hacer el trabajo.
* El diseño tendría que ser rastreable por el modelo de análisis. Ya que un único elemento del modelo de diseño a menudo puede remontarse a múltiples requisitos, es necesario tener un medio para observar cómo los requisitos han sido satisfechos por el modelo de diseño.
* El diseño no tendría que reinventar la rueda. Los sistemas se construyen utilizando un conjunto de patrones de diseño, muchos de los cuales probablemente han sido utilizados anteriormente. Estos patrones deberían ser escogidos como alternativa a la reinvención. Se dispone de poco tiempo y recursos limitados; tiempo de diseño tendría que invertirse en representar ideas verdaderamente nuevas integrando patrones que ya existan (siempre y cuándo esto sea posible).
* El diseño debe "minimizar la distancia intelectual" entre el software y el problema tal y como existe en el mundo real. Esto es, la estructura del diseño de software debe, siempre que sea posible, imitar la estructura del dominio del problema.
* El diseño tiene que exhibir uniformidad e integración. Un diseño es uniforme si resulta plenamente coherente. Para conseguir esto, las reglas de estilo y formato han de ser definidas para el equipo de diseño antes de que comience el trabajo de diseño. Un diseño está integrado si se ha tomado la molestia en definir interfaces entre componentes de diseño.
* El diseño tendría que ser estructurado para adaptarse al cambio. Los conceptos de diseño que se exponen en la próxima sección, habilitan al diseño para conseguir este principio.
* El diseño tendría que estar estructurado para degradarse suavemente, incluso cuándo los datos, los acontecimientos o las condiciones operativas son irregulares. El software bien diseñado nunca debería "explotar"; debe ser diseñado para adaptarse a circunstancias inusuales, y si tuviera que terminar su ejecución, habrá de hacerlo de la manera más grácil posible.
* El diseño no es codificación, la codificación no es diseño. Incluso cuándo los diseños detallados de procesos están creados para componentes del programa, el nivel de abstracción del modelo de diseño es más alto que el del código fuente. Las únicas decisiones de diseño del nivel de codificación tendrían que referirse a pequeños detalles de implementación para habilitar la codificación del diseño de procesos.
* La calidad del diseño tendría que ser evaluado cuando se está creando, no después. Una variedad de conceptos y medidas de diseño están disponibles para asistir al diseñador en la evaluación de la calidad durante el proceso de desarrollo.
* El diseño tendría que ser revisado para minimizar los errores conceptuales (semánticos). A veces hay una tendencia a centrarse en minucias cuándo se revisa el diseño. El equipo de diseño tendría que asegurarse de que los elementos conceptuales importantes del diseño (omisiones, ambigüedad, incongruencias) han sido tratados antes de preocuparse por la sintaxis del modelo de diseño.

## Conceptos de diseño

Los conceptos de diseño proporcionan al diseñador de software una base sobre la que se pueden aplicar métodos más sofisticados. El conjunto de conceptos fundamentales del diseño ha evolucionado. Son los siguientes:
* Abstracción: la abstracción es el proceso o resultado de la generalización reduciendo el contenido de información de un concepto o un fenómeno observable, típicamente para retener información única que es pertinente para un propósito particular. Es el acto de Representar características esenciales sin incluir los detalles de fondo o explicaciones.
* Refinamiento: es el proceso de elaboración. Una jerarquía se desarrolla descomponiendo una declaración macroscópica de función de un modo sensato hasta que se logre obtener declaraciones del lenguaje de programación. En cada paso, una o varias instrucciones de un programa dado se descomponen en instrucciones más detalladas. La abstracción y El Refinamiento son conceptos complementarios .
* Modularidad: La arquitectura de software está dividida en componentes llamados módulos.
* Arquitectura de software - se refiere a la estructura global del software y las maneras en que esa estructura proporciona integridad conceptual al sistema. Una buena arquitectura de software amortizará la inversión en cuanto al resultado deseado del proyecto, p. ej. en el rendimiento, la calidad, el programa y el coste.
* Jerarquía de control: Una estructura de programa que representa la organización de un componente e implica una jerarquía de control.
* Estructural Partitioning: La estructura de programa puede ser dividida horizontal y verticalmente. Las particiones horizontales definen ramas separadas de jerarquía modular para cada función importante. Las particiones verticales sugiere que el control y el trabajo tendrían que ser distribuidos de arriba abajo en la estructura de programa.
* Estructura de datos: es una representación de la relación lógica entre los elementos individuales de los datos.
* Procedimiento de software: centra en el procesamiento de cada módulo individualmente.
* Ocultar Información: los módulos tendrían que ser especificados y diseñados de modo que la información contenida dentro de un módulo es inaccesible a otros módulos, que no tienen ninguna necesidad de conocer esa información.
En su modelo de objeto, Grady Booch menciona abstracción, encapsulación, modularización y jerarquía como principios fundamentales del diseño de software. El acrónimo PHAME (del inglés: Principles of Hierarchy, Abstraction, Modularisation, and Encapsulation) se utiliza a veces para referirse a estos cuatro principios fundamentales.

## Consideraciones de diseño

Hay muchos aspectos a considerar en el diseño de una pieza de software. La importancia de cada consideración tendría que reflejar los objetivos y expectativas para los que el software está siendo creado. Algunos de estos aspectos son:
* Compatibilidad - El software es capaz de operar con otros productos que están diseñado para interoperar con otros productos. Por ejemplo, una pieza de software puede ser compatible con una versión más vieja de sí misma.
* Extensibilidad - Las capacidades nuevas pueden añadirse al software sin cambios importantes a la arquitectura subyacente.
* Modularidad - El software resultante contiene componentes bien definidos e independientes que llevan a una mejor mantenibilidad. Los componentes podrían ser entonces implementados y probados en aislamiento antes de ser integrados en el sistema de software deseado. Esto permite la división de trabajo en un proyecto de desarrollo del software.
* Tolerancia a los fallos - El software es resistente y capaz de recuperarse de los fallos de componente.
* Mantenibilidad - Una forma de medir cómo se consiguen los arreglos de errores y las modificaciones funcionales. Una alta mantenibilidad puede ser producto de la modularidad y la extensibilidad.
* Fiabilidad (durabilidad del Software) - El software es capaz de realizar una función bajo determinadas condiciones durante un periodo específico de tiempo.
* Reusabilidad- La capacidad de utilizar algunos o todos los aspectos del software existente en otros proyectos con pocas o ninguna modificación.
* Robustez - El software es capaz de operar bajo tensión o tolerar una entrada imprevisible o inexistente. Por ejemplo, puede ser diseñado con resistencia a condiciones malas de memoria.
* Seguridad - El software es capaz de resistir a influencias y actos hostiles.
* Usabilidad - La interfaz de usuario del software tiene que ser utilizable para su audiencia objetivo. Los valores por defecto para los parámetros tienen que ser escogidos de modo que sean una buena elección para la mayoría de los usuarios.
* Rendimiento - El software realiza sus tareas dentro de una ventana temporal que es aceptable para el usuario, y no requiere demasiada memoria.
* Portabilidad - El software tendría que ser utilizable a través de un número de entornos y condiciones diferentes.
* Escalabilidad - El software se adapta bien a un número creciente de datos o usuarios.

## Lenguaje de modelado

Un lenguaje de modelado es cualquier lenguaje artificial que puede usarse para expresar información, conocimiento o sistemas en una estructura que está definida por un conjunto consistente de reglas. Estas reglas se utilizan en la interpretación de los componentes dentro de la estructura. Un lenguaje de modelado puede ser gráfico o textual. Ejemplos de lenguas de modelado gráfico para diseño de software son:
* Architecture description language (ADL) es un lenguaje que se usa para describir y representar la arquitectura de software de un sistema de software.
* Business Process Modeling Notation (BPMN) es un ejemplo de Lenguaje de modelado.
* EXPRESS and EXPRESS-G (ISO 10303-11) es lenguaje de modelado estándar internacional de propósito general.
* Extended Enterprise Modeling Language (EEML) se usa generalmente para modelado de procesos de negocio a través de varias capas.
* Flowchart es una representación esquemática de un algoritmo o proceso.
* Fundamental Modeling Concepts (FMC) es un sistema de modelado para sistemas software intensivo.
* IDEF es una familia de lenguajes de modelado, entre los cuales destacan IDEF0 para modelado funcional y IDEF1X para modelado de información.
* Jackson Structured Programming (JSP) es un método de programación estructurada basado en las correspondencias de las corrientes de datos y la estructura del programa.
* LePUS3 es un lenguaje de diseño de descripciones orientado a objetos y un lenguaje de especificación formal que sirve sobre todo para modelar grandes programas orientados a objetos (Java, C++, C#) y patrones de diseño.
* Unified Modeling Language (UML) es un lenguaje de modelado general para describir software en cuanto a su comportamiento y su estructura.
* Alloy (specification language) es un lenguaje de propósito general para expresar restricciones de estructura complejas y comportamiento en un sistema de software.
* Systems Modeling Language (SysML) es un nuevo lenguaje de modelado de propósito general para ingeniería de sistemas.
* Service-oriented modeling framework (SOMF)

## Patrones de diseño

Un diseñador de software o arquitecto puede identificar un problema de diseño que ha sido visitado y quizás incluso solucionado por otros anteriormente. La plantilla o patrón que describe una solución a un problema común se conoce como patrón de diseño. La reutilización de tales patrones puede ayudar a agilizar el proceso de desarrollo del software.

## Técnica

La dificultad de utilizar el término "diseño" en la relación a software es que en algunos sentidos, el código fuente de un programa es el diseño para el programa que produce. Hasta el punto en que esto es cierto, el "diseño de software" refiere al diseño del diseño. Edsger W. Dijkstra se refirió a este layering de niveles semánticos como la "novedad radical" de la programación, y Donald Knuth utilizó su experiencia escribiendo TeX para describir la inutilidad de intentar diseñar un programa antes de implementarlo:

## Uso

La documentación de diseño de software puede ser revisada o presentada para permitir restricciones, especificaciones e incluso para ajustar requisitos antes de programar. La redefinición puede ocurrir después de revisar una simulación programada o prototipo. Es posible diseñar software en el proceso de programar, sin un plan o análisis de requisitos, pero para proyectos complejos esto no sería factible. Un diseño por separado con anterioridad a programar permite a los diseñadores multidisciplinares y expertos colaborar con programadores altamente especializados en software útil y técnicamente seguro.