Skip to content

Latest commit

 

History

History
789 lines (499 loc) · 29.8 KB

arquitectura-2020.md

File metadata and controls

789 lines (499 loc) · 29.8 KB
marp
<style> h1 { text-align: center; } h2 { color: darkblue; text-align: center; } </style>

DISEÑO DE SISTEMAS SOFTWARE

<style scoped> h2 { text-align: left; } </style>

Bloques

  1. Principios de diseño OO
  2. Patrones de diseño
  3. Arquitectura de software

ARQUITECTURA DE SOFTWARE


Índice de contenidos

  1. Introducción
  2. Componentes software
  3. Principios arquitectónicos
  4. Patrones de arquitectura
  5. Modelado de arquitecturas

Introducción


Arquitectura

  • La arquitectura de un sistema software es el conjunto de decisiones de diseño principales realizadas sobre el sistema.

  • Son los planos para la construcción y la evolución de un sistema software.

  • Una arquitectura de referencia se refiere al conjunto de decisiones de diseño que se pueden aplicar simultáneamente a varios sistemas relacionados, dentro de un dominio de aplicación y con puntos de variación definidos explícitamente. Sirven de base para las lineas de productos software.


Atributos de calidad

En el diseño de la arquitectura hay que tener presente no solo los requisitos funcionales, sino también las propiedades no funcionales del software, que definen sus aspectos de calidad:

  • Adecuación funcional: corrección y completitud
  • Fiabilidad: disponibilidad, tolerancia a fallos y capacidad de recuperación
  • Eficiencia: rendimiento y consumo adecuado de recursos
  • Operabilidad: usabilidad y accesibilidad
  • Seguridad: confidencialidad, integridad y no repudio
  • Compatibilidad: reemplazabilidad e interoperabilidad con sistemas externos y legados
  • Mantenibilidad: facilidad de modificación, de extensión, de prueba y de reutilización
  • Transferibilidad: portabilidad, adaptabilidad y facilidad de instalación

Algunos de estos aspectos son, en ocasiones, "conflictivos”.


Decisiones de diseño

  • Estructura del sistema: v.g. "Los elementos arquitectónicos se organizarán y compondrán exactamente de forma que..."
  • Interacción: v.g. "La comunicación entre los elementos del sistema se hará mediante notificaciones de eventos"
  • La implementación del sistema: v.g. "Los componentes de interfaz de usuario se construirán usando Java Swing"
  • Tácticas para abordar las propiedades no funcionales del sistema: v.g. "La confiabilidad del sistema se asegurará mediante módulos de procesamiento duplicados"
  • Aspectos de negocio tales como el tiempo de lanzamiento al mercado, coste y beneficio, etc.,

Importancia de la arquitectura software

La finalidad de la arquitectura es facilitar el desarrollo, despliegue, operación y mantenimiento del sistema software.

  • Proporcionan un lenguaje común para expresar, negociar y resolver los diferentes intereses de los participantes
  • Condicionan la estructura organizativa del equipo de desarrollo
  • Permite una estimación más exacta de los costes y planificación
  • Las arquitecturas pueden constituirse como la base para la formación de nuevos miembros del proyecto

Granularidad

Las aplicaciones crecen en tamaño y complejidad y se requiere algún tipo de organización

  1. La clase es de un grano demasiado fino como unidad de organización
  2. En UML, Java y otros lenguajes se da el concepto de paquete (package)
  3. En general puede hablarse de módulos o componentes, como agrupaciones lógicas de declaraciones que pueden importarse en otros programas

Componentes software



Arquitectura basada en componentes

La arquitectura de un sistema software es la forma dada al sistema por aquellos que lo construyen. La forma es la división del sistema en componentes, la disposición de esos componentes y la manera en que se comunican entre sí.

Bob Martin

LEGO for Software Engineering, width:550px


Definición de componente software

Un componente software es una unidad de composición binaria con interfaces especificadas contractualmente y dependencias explicitas del contexto. Un componente software se puede instalar independientemente, está sujeto a composición por terceros y no tiene estado.

Szyperski

  • Son la expresión tangible de los principios de encapsulación, abstracción y modularidad.

Unidad de composición

  • La verdadera industrialización del software (en contrapartida al desarrollo artesanal) se basa, como en el resto de ingenierias, en el desarrollo a partir de componentes prefabricados que pueda disponer la empresa de desarrollo.

  • La existencia y disponibilidad de los componentes deben considerarse durante todo el ciclo de vida del software, desde el planteamiento de la oferta y el análisis de requisitos, hasta el diseño, implementación y pruebas.


Binaria (machine-procesable)

  • Este termino hace referencia a la necesidad de que los componentes sean directamente procesables por la maquina, es decir, que no se requiera intervención humana (compilación, preprocesamiento, etc.) para que puedan funcionar.
  • Así pues, un trozo de código no podríamos considerarlo como un componente software.

Interfaces

  • Las interfaces son la vía de comunicación de los componentes con el exterior. Las interfaces están compuestas por cero o más métodos.
  • Podemos tener lenguajes de programación como C++ o PHP, en donde cada interfaz tiene una sola implementación, o lenguajes como Java o C#, donde una misma interfaz puede ser implementada por distintas clases.
  • Las interfaces de entrada está pensadas para que el cliente pueda usar las implementaciones que proporciona un determinado componente. Sin embargo, las interfaces de salida están pensadas para ser usadas desde dentro del componente.

Especificación contractual

  • Un contrato es la especificación de un conjunto de restricciones de uso de un determinado componente software.
  • Suelen recogerse mediante hojas de especificación en lenguaje natural o en formato electrónico procesable por la maquina. Las especificaciones electrónicas son las mejores, ya que así podremos observar posibles errores en tiempo de compilación.
  • Los contratos deben contemplar la sintaxis de las llamadas a los métodos, su semántica y aspectos no funcionales como la trazabilidad, portabilidad, persistencia, etc.

Dependencias explícitas del contexto

Son los elementos que se necesitan para que el componente pueda funcionar correctamente. El contexto de ejecución requerido consta de:

  • Las configuraciones hardware necesarias.
  • El software de sistema requerido (v.g. runtime del lenguaje de programación, middleware, sistema operativo, protocolos de red, drivers de dispositivos, etc.)
  • La disponibilidad de recursos específicos (v.g. ficheros de datos, directorios, etc.)
  • La interfaz de salida requeridas (proporcionadas por otros componentes)

Instalación independiente

Tiene dos vertientes diferentes:

  • Independencia de vendedor: Al instalar un determinado componente, no se requiere la instalación de otro de un determinado fabricante.
  • Unidad atómica: El componente se instala completamente o no se instala, por tanto no existe instalación parcial.

Composición por terceros (y sin estado)

  • Un componente debe tener sentido tanto para la organización que lo desarrolla como para otras. Si solo lo tiene para el propio fabricante, no deberíamos considerarlo componente.

  • Los componentes no tienen estado interno, por lo que no cambia por dentro. Si un componente tuviese estado, entonces el mantenimiento de los componentes seria diferente para cada cliente.


Cuestionario sobre componentes (I)

  • ¿Un objeto en Java es un componente?

  • ¿Un botón de una determinada GUI es un componente?

  • ¿Una clase Java es un componente?

  • ¿Un paquete en Java es un componente?


Cuestionario sobre componentes (I) [respuestas]

  • ¿Un objeto en Java es un componente? No, ya que tiene estado, no puede instalarse, etc.

  • ¿Un botón de una determinada GUI es un componente? No, debido a que tienen estado, y son instalables, entre otros.

  • ¿Una clase Java es un componente? No, debido a que no es “binario” y no puede instalarse.

  • ¿Un paquete en Java es un componente? Un paquete en Java supera todas las condiciones para ser un componente, excepto que un paquete no puede instalarse independientemente. Así pues, no es un componente.


Cuestionario sobre componentes (II)

  • ¿Un fichero mp3 es un componente?

  • ¿Un servicio web es un componente?

  • ¿La API para trabajar con XML en Java –Xerces.jar- es un componente?

  • ¿La librería de Linux Glibc-2.3.a, es un componente?


Cuestionario sobre componentes (II) [respuestas]

  • ¿Un fichero mp3 es un componente? No, ya que no tiene interfaz, no sirve para componer, etc.. Es un recurso.

  • ¿Un servicio web es un componente? Si, ya que pasa todas las condiciones.

  • ¿La API para trabajar con XML en Java –Xerces.jar- es un componente? Si, ya que pasa todas las condiciones.

  • ¿La librería de Linux Glibc-2.3.a, es un componente? Si, lo podemos considerar como componente.


Principios de Diseño Arquitectónico


Principios de diseño SOLID

  • S ingle responsibility principle A class should only have a single responsibility, that is, only changes to one part of the software's specification should be able to affect the specification of the class.

  • O pen–closed principle "Software entities ... should be open for extension, but closed for modification."

  • L iskov substitution principle "Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program."

  • I nterface segregation principle "Many client-specific interfaces are better than one general-purpose interface."

  • D ependency inversion principle One should "depend upon abstractions, [not] concretions."


Implicaciones de SOLID en arquitectura

  • S ingle responsibility principle Un módulo debería ser solo responsable de uno y solo un actor o stakeholder.

  • O pen–closed principle El comportamiento de un artefacto software debe ser extensible sin tener que modificarlo.

  • L iskov substitution principle Inicialmente vinculado a la herencia de clases, hoy se considera más ligado a la acción de remplazar las implementaciones de interfaces (locales o remotas ReST).

  • I nterface segregation principle No depender de módulos que contienen más de lo que se necesita. Depender de algo que trae "equipaje" innecesario puede ser origen de problemas.

  • D ependency inversion principle Es importante no mencionar nunca el nombre de algo concreto y volátil en el código, referirse solo a abstracciones.


Ejemplo de OCP y DIP en arquitectura (diagrama UML de componentes)

Ejemplo de OCP, width:550px


Ejemplo de OCP y DIP en arquitectura (diagrama UML de clases)

Ejemplo de OCP, width:700px


Ejemplo de violación de LSP en arquitectura
  • Un servicio agregador de taxis (uber, cabify, mitaxi, acme, etc.)
  • La URI con que se llama al taxi se guarda en la base de datos en formato ReST: mitaxi.com/driver/Bob
  • El agregador añade la información de pedido y hace PUT a la URI:
    mitaxi.com/driver/Bob
      /pickupAddress/24 Maple St.
      /pickupTime/153
      /destination/ORD
    
  • Todos los taxis de diferentes compañías deben cumplir la misma interfaz ReST.
  • La compañía ACME resulta que abrevia el destino en la URI con dest

  • Ahora la petición hay que construirla siguiendo una reglas distintas para cada conductor: if (driver.getDispatchUri().startsWith("acme.com")) ...

  • Pero meter "acme.com" en el código puede ser origen de fallos y brechas de seguridad. Aún peor: ACME compra a MiTaxi y unifica los sistemas informáticos.

  • Las interfaces de los servicios ReST no son sustituibles, por lo que la mejor opción es definir un módulo adicional que decide el formato en función de la URI:

URI Dispatch format
acme.com pickupAddress/%s/pickupTime/%s/dest/%s
*.* pickupAddress/%s/pickupTime/%s/destination/%s

Principios de Cohesión y Acoplamiento de Componentes

  • REP: Reuse/Release Equivalente Principle
  • CRP: Common Reuse Principle
  • CCP: Common Closure Principle
  • ADP: Acyclic Dependencies Principle

Principio REP: Equivalencia de Reutilización/Entrega

The granule of reuse is the granule of release. Either all of the classes inside the package are reusable, or none of them are. Only components that are released through a tracking system can be effectively reused.

Robert C. Martin

  • ¿Se reutiliza código cuando se hace copia-pega? ¡No! Se reutiliza código si y sólo si no hace falta mirar el código fuente más allá de la parte pública del componente (ficheros de cabecera, etc.)

  • Un cliente de una biblioteca liberada lo es de toda la biblioteca, no de parte de ella. Por ello, el grano de reutilización no puede ser menor que el grano de entrega

  • El autor debe distribuir/hacer entregas regulares de distintas versiones del componente/biblioteca.


  • Estrategias DevOps para

  • Hay muchas herramientas de gestión de componentes y sus dependencias con los que poder reutilizar las bibliotecas y frameworks creados por otros

    • Maven, para el lenguaje Java
    • NPM, para el lenguaje Javascript
    • Conan, para el lenguaje C/C++
    • NuGet, para el entorno .NET de Microsoft
    • PyPi, para el lenguaje Python
    • RubyGems, para el lenguaje Ruby

Principio CRP: Reutilización en Común

Don’t force users of a component to depend on things they don’t need. The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.

Robert C. Martin

  • Cuando alguien decide usar un componente, se crea una dependencia sobre todo el componente.

  • No es bueno tener que re-validar una aplicación porque hay que liberar o entregar una versión del componente provocada por cambios hechos en clases que no importaban.

  • CRP dice más sobre qué clases no deben ir juntas que sobre las que deben ir juntas.

CRP es la versión genérica del ISP:

  • ISP aconseja no depender de interfaces con métodos que no usemos
  • CRP aconseja no depender de componentes que tengan clases que no usemos

Ejemplo
  • Supongamos que un sistema $S$ quiere incluir un framework $F$ y que los creadores de $F$ lo han acoplado a una base de datos $D$:

    $S \rightarrow F \rightarrow D$

  • Si $D$ contiene características que $F$ no usa y que a $S$ tampoco le interesan;

    • los cambios en esas características de $D$ forzarán un redespliegue de $F$ y de $S$;
    • los fallos en $D$ causarán fallos en $F$ y $S$.

Principio CCP: Clausura Común

Gather into components those classes that change for the same reasons and at the same times. Separate into different components those classes that change at different times and for different reasons.

Robert C. Martin

  • Si hay que cambiar el código, ¿dónde es mejor que estén los cambios? ¿en un mismo componente, o repartidos por varios componentes?

  • Está relacionado con los principios SRP y OCP

  • Como no es posible garantizar al 100% el cierre de OCP $\implies$ el cierre debe ser estratégico $\implies$ diseñar los sistemas para que estén cerrados a los cambios más probables que podamos anticipar.


Principio ADP: Dependencias Acíclicas

There must be no cycles in the coimponent dependency graph

Robert C. Martin

  • El grafo de dependencias entre components debe ser un DAG (Directed Acyclic Graph)

  • Hay que particionar el entorno de desarrollo en componentes "liberables" por separado.

  • Varios equipos de trabajo distribuidos pueden hacer cambios a cada componente por separado, lo que puede inducir nuevas dependencias entre componentes $\implies$ Hay que gestionar la estructura de dependencias de los componentes


Ejemplo: estructura de un sistema (diagrama sin ciclos)

Diagrama de componentes inicial, width:700px


  • ¿A quién afecta la liberación de una nueva versión de Presenters por sus responsables?
    Solo Mainy View se ven afectadas

  • ¿A quiénes afecta la ejecución de un test unitario en Presenters?
    Interactors y Entities (deberían ser mocked)

  • ¿En qué orden se libera una nueva versión del sistema? Entities, Database Interactors, Authorizer Presenters, View & Controllers Main


Ejemplo: estructura de un sistema (diagrama con ciclos)
  • Un cambio de requisitos fuerza a introducir una nueva dependencia entre la clase Entities::User y la clase Authorizer::Permissions\

Ciclo de dependencias, width:700px


Problemas:
  • Los desarrolladores de Database saben que para liberarla, deben hacerla compatible con Entities
  • Pero ahora Database depende también de Authorizer y de Interactors

1️⃣ $\implies$ ahora Database es mucho más difícil de liberar, porque:

  • Los cambios que haga cualquier responsable de alguno de estos tres componentes afectarán al resto

2️⃣ $\implies$ el desarrollo de pruebas es más difícil:

  • si se quiere probar Entities, antes hay que construir e integrar Authorizer y Interactors (más mocks!)

Ruptura de ciclos

Dos posibles soluciones:

  1. Aplicar el principio DIP
    • Crear una interfaz con los métodos que necesita la clase User
    • Incluir la interfaz en Entities
    • Heredar de la interfaz desde Authorizer

Inversión de dependencias entre dos componentes


  1. Crear un componente nuevo (Permissions) del que dependan ambos (Authorizer y Entities)

Nuevo componente en el diagrama final


Patrones de arquitectura


Patrones de arquitectura

  • Un patrón (o un estilo) arquitectónico es una colección (con nombre) de decisiones de diseño arquitectónico que son aplicables a un problema recurrente de diseño que tienen en cuenta diferentes contextos de desarrollo de software en los que aparece el problema.

  • Los estilos/patrones no tienen porqué ser excluyentes entre sí. Pueden combinarse.

  • Lectura recomendada: Buschman et al.: Pattern-Oriented Software Architecture (POSA), chapters 1-2.


Arquitecturas de despliegue


Centralized architecture

  • Toda la computación se lleva a cabo en una única máquina.
  • Aplicaciones de consola o de escritorio
  • Con lenguajes portables logramos la independencia del S.O.

Centralized architecture


Client server architecture

  • Es el patrón más utilizado tanto en aplicaciones legacy como en las más actuales.
  • Se basa en tecnologías como CORBA, Java RMI, HTTP, SOAP y REST para el envío y recepción de datos entre cliente y servidor.
  • Los servidores residen en centros de datos on-premise o en cloud, mientras que los clientes (ligeros o pesados) pueden ejecutarse en diferentes dispositivos.

Client & server architecture, width:500px


Peer to Peer architecture

  • Red de nodos que se comportan como iguales entre sí para proporcionar aplicaciones como:
    • Monedas virtuales: bitcoins
    • Intercambio de ficheros: torrent
    • Sistemas de CCTV
    • Videoconferencias: WebRTC

Peer to peer architecture, height:370px


Arquitecturas de desarrollo


Spaghetti architecture

  • Es, en realidad, un anti-patrón de diseño.
  • Código no modular que incumple los principios de diseño Spaghetti architecture, width:600px

Pipes and filters architecture

  • Adecuado para sistemas de procesamiento de flujos de datos
  • Ejemplos:
    • procesos ETL: extracción, transformación y carga de datos sobre datawarehouses
    • compiladores: análisis léxico, sintáctico, semántico, generación de código, etc.

Pipes & filters architecture , width:1200px


Blackboard architecture

  • Útil para problemas con soluciones no-determinísticas sin soluciones óptimas habitual en sistemas de aprendizaje automático.
  • Dividir la tarea general en pequeñas tareas con soluciones determinísticas, usando un repositorio de datos compartido del cual toman datos y depositan datos.
  • Ejemplos: reconocimiento de texto en lenguaje natural, de voz o imágenes Blackboard architecture, width:1200px

Microkernel architecture

  • Patrón natural para implementar aplicaciones basadas en productos.
  • El kernel sólo tiene la funcionalidad básica.
  • Ejemplos: entornos de desarrollo integrados, navegadores web, etc.

Microkernel architecture, width:700px


Reflection architecture

  • Reflexión: capacidad de un programa para “mirar en su interior”, accediendo y manipulando su comportamiento y estructura en tiempo de ejecución
  • Frameworks para meta-programación o programación genérica: Apache ISIS, OpenXava, etc. Reflection architecture

MVC architecture

  • Propone la separación de responsabilidades:
    • Modelo: Lógica de acceso a los datos
    • Vista: Presentación de los datos y de las acciones a realizar
    • Controlador: Gestión de eventos de usuario
  • Muy popular y utilizado en frameworks web, como Laravel, Spring MVC, etc.
  • Existen otros patrones similares (MV*) como MVVM, MVP…
    MVC architecture

Layered architecture

  • División en capas de diferentes con diferentes responsabilidades, siendo la arquitectura en 3 capas (presentación, negocio y acceso a datos) muy habitual en aplicaciones empresariales
  • Es combinable con el MVC, de modo que la Vista y el Controlador forman la capa de presentación en una arquitectura en 3 capas

Layered architecture, width:680px


Hexagonal architecture (Ports & Adapters pattern)

  • Evolución de la arquitectura anterior que logra eliminar las dependencias de lógica de negocio con cualquier tecnología o framework, interfaz de usuario, mecanismo de persistencia o cualquier agente externo.

Hexagonal architecture, width:700px


Layered vs hexagonal architecture

Layered vs hexagonal architecture, width:630px


Modelado de arquitecturas


Lenguajes de descripción de arquitecturas

  • Un modelo arquitectónico es un artefacto que captura, total o parcialmente, las decisiones de diseño de la arquitectura de un sistema.
  • Una notación de modelado arquitectónico es un lenguaje para capturar las decisiones de diseño.
  • Se denominan Architecture Description Language (ADL)
  • Los lenguajes pueden ser gráficos, textuales, informales, específicos de dominio, etc.
  • Ejemplos: UML, Archimate, C4Model

C4Model

The C4 model for visualising software architecture

https://c4model.com/