marp |
---|
- Principios de diseño OO
- Patrones de diseño
- Arquitectura de software
- Introducción
- Componentes software
- Principios arquitectónicos
- Patrones de arquitectura
- Modelado de arquitecturas
-
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.
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”.
- 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.,
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
Las aplicaciones crecen en tamaño y complejidad y se requiere algún tipo de organización
- La clase es de un grano demasiado fino como unidad de organización
- En UML, Java y otros lenguajes se da el concepto de paquete (package)
- En general puede hablarse de módulos o componentes, como agrupaciones lógicas de declaraciones que pueden importarse en otros programas
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
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.
-
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.
- 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.
- 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.
- 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.
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)
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.
-
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.
-
¿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?
-
¿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.
-
¿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?
-
¿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.
-
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."
-
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.
- 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 |
- REP: Reuse/Release Equivalente Principle
- CRP: Common Reuse Principle
- CCP: Common Closure Principle
- ADP: Acyclic Dependencies Principle
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
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
-
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$ .
- los cambios en esas características de
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.
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
-
¿A quién afecta la liberación de una nueva versión de
Presenters
por sus responsables?
SoloMain
yView
se ven afectadas -
¿A quiénes afecta la ejecución de un test unitario en
Presenters
?
Interactors
yEntities
(deberían ser mocked) -
¿En qué orden se libera una nueva versión del sistema?
Entities
,Database
Interactors
,Authorizer
Presenters
,View
&Controllers
Main
- Un cambio de requisitos fuerza a introducir una nueva dependencia entre la clase
Entities::User
y la claseAuthorizer::Permissions
\
- Los desarrolladores de
Database
saben que para liberarla, deben hacerla compatible conEntities
- Pero ahora
Database
depende también deAuthorizer
y deInteractors
1️⃣ 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️⃣
- si se quiere probar
Entities
, antes hay que construir e integrarAuthorizer
yInteractors
(más mocks!)
Dos posibles soluciones:
- 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
- Crear una interfaz con los métodos que necesita la clase
- Crear un componente nuevo (
Permissions
) del que dependan ambos (Authorizer
yEntities
)
-
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.
- 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.
- 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.
- 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
- 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.
- Ú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
- 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.
- 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.
- 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…
- 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
- 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.
- 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
The C4 model for visualising software architecture