sintesis

¿Por qué?

  • Inefectividad, ineficacia y/o ineficiencia, del Proyecto Software

    • porque tiene malas variables en su economía:

      • ámbito incumplido y/o

      • tiempo incumplido y/o

      • coste incumplido;

    • porque tiene mala calidad del software, fiabilidad, usabilidad, interoperatividad, seguirdad, …​ (-ilities)

    • porque tiene mala mantenibilidad

      • viscoso, porque no se puede entender con facilidad y/o

      • rígido, porque no se puede cambiar con facilidad y/o

      • frágil, porque no se puede probar con facilidad y/o

      • inmovil, porque no se puede reutilizar con facilidad y/o

    • porque tiene complejidad arbitraria

davidProyectoImplantacionDiseñoMal

arbolNoMantenible

Arquitectura

arquitectura

Construcción sencilla Construcción compleja

casaPerro

casaLujo

  • Requiere

    • Modelado sencillo

    • Proceso sencillo

    • Técnicas sencillas

    • Herramientas sencillas

  • Requiere

    • Modelado complejo

    • Proceso complejo

    • Técnicas complejas

    • Herramientas complejas

¿Qué?

La industria del software se complace en tomar palabras y estirarlas en un sin número de significados sutilmente contradictorios. Uno de los mayores afectados es la "arquitectura". Tiendo a ver la arquitectura como una de esas palabras que suenan impresionantes, usadas principalmente para indicar que estamos hablando de algo que es importante
— Martin Fowler
Software Architecture

Arquitectura del Sistema

  • La Arquitectura del sistema selecciona un conjunto de bloques de construcción funcionales, hardware, software, firmware, etc.

    • Los bloques de construcción que son componentes software tienen:

      • un conjunto de casos de uso, clases relacionadas, datos, etc

      • La Arquitectura del software se centra en paquetes, no se centra en los detalles de implementación o la aplicación de patrones de diseño, a nivel de clases

arquitecturaSistema

Arquitectura del Software

Analogía con la arquitectura de edificios, proponemos el siguiente modelo de arquitectura del software con tres clases de elementos arquitecturales: elementos de procesamiento, componentes que suministran la transformación de los elementos de datos; elementos de datos, contienen la información usada y transformada; y conexiones entre elementos, son el pegamento que une juntas las diferentes piezas de la arquitectura,los cuales pueden ser tanto de procesamiento, de datos o de ambos
— Perry y Wolf
La arquitectura de un sistema de software intensivo es la estructura o estructuras del sistema, que comprenden elementos de software, las propiedades visibles externamente de esos elementos y las relaciones entre ellos
— Carnigie-Mellon University
La organización fundamental de un sistema incorporado en sus componentes, sus relaciones con otros y su entorno y las principales guías de su diseño y evolución
— IEEE
Una arquitectura es el conjunto de decisiones significativas sobre la organización del un sistema software, la selección de los elementos estructurales y sus interfaces por los que el sistema está compuesto junto con su comportamiento como se especifica en sus colaboraciones entre estos elementos, la composición de estos elementos estructurales y de comportamiento en subsistemas progresivamente más grandes y el estilo de arquitectura que guían la organización – estos elementos, sus interfaces, sus colaboraciones y su composición
— Booch, Rumbaugh, and Jacobson
Rational Unified Process
  • …​ junto con el estilo arquitectónico que guía esta organización dado por:

  • Restricciones no funcionales (rendimiento, plataforma, …)

  • Tecnologías (protocolos, bases de datos, …)

  • Reusabilidad (diccionarios de datos, API’s, …)

  • Economía (sistemas heredados, frameworks, …)

  • Compromisos de uso (disponibilidad, amigabilidad, …)

  • Flexibilidad al cambio (patrones de software, cortafuegos, …)

  • y aspectos estéticos (C2, CMMI, …)

  • Sistema = Forma + Funcionalidad

  • Sistema = Arquitectura + Casos de Uso

    • Forma = Arquitectura

    • Funcionalidad = Casos de Uso

  • Compartir una estructura de alto nivel y mecanismos clave similares

    • “parábola del ciego y el elefante”

height32

¿Para qué?

  • Efectividad, eficacia y eficiencia, del Proyecto Software

    • porque tiene buenas variables en su economía:

      • ámbito cumplido y

      • tiempo cumplido y

      • coste cumplido;

    • porque tiene buena calidad del software, fiabilidad, usabilidad, interoperatividad, seguirdad, …​ (-ilities)

    • porque tiene buena mantenibilidad

      • fluido, porque se puede entender con facilidad y/o

      • flexible, porque se puede cambiar con facilidad y/o

      • fuerte, porque se puede probar con facilidad y/o

      • reusable, porque se puede reutilizar con facilidad y/o

    • porque tiene complejidad inherente

davidProyectoImplantacionDiseño

arbolMantenible

Objetivos
  • Comprender el sistema.

  • Fomentar la reutilización.

  • Evolucionar el sistema.

  • Organizar el desarrollo.

  • Cientos de clases en docenas de paquetes pequeños poco acoplados y altamente cohesivos

  • La industria de la fontanería durante mucho tiempo ha sido normalizado. Contratistas de fontanería se benefician de componentes estándar.

    • Al hacer coincidir las dimensiones de componentes "creativos" obtenidos a partir de aquí y allá, el fontanero selecciona a partir de un conjunto estandarizado que siempre encajan.

  • La industria del software aún no ha alcanzado el nivel de estandarización que muchos dominios de hardware han realizado, pero buenas arquitectura e interfaces explícitas son pasos en esa dirección.

  • El sistema debería ser fácil de cambiar, esto es que los desarrolladores deberían ser capaces de cambiar partes del diseño e implementación sin tener que preocuparse sobre el efecto del cambio reverberando inesperadamente a través del sistema

  • Dividiendo el sistema en subsistemas con interfaces claramente definidos y haciendo responsable a un grupo o un individuo para cada subsistema, el arquitecto puede reducir la carga de comunicaciones entre grupos de trabajo sobre distintos subsistemas

  • Un proceso muy simple, racional y efectivo, eficaz y eficiente, que se utiliza ampliamente es descomponer el entorno de desarrollo en paquetes entregables:

  • Los paquetes se convierten en unidades de trabajo que son responsabilidad de un equipo de ingenieros.

  • Cuando consiguen un paquete funcionando, lo entregan para el uso de los otros paquetes, equipos. Todos dependen de la versión de entregada.

  • Luego siguen modificando su paquete en sus propias áreas privadas. Según se hacen las nuevas versiones, otros equipos pueden decidir si adoptan o no de inmediato la nueva versión.

    • Si deciden no hacerlo, simplemente siguen usando la versión antigua.

    • Una vez que deciden que están listos, comienzan a utilizar la nueva versión.

  • Por tanto, ninguno de los equipos está a merced de los demás.

    • Los cambios realizados en un solo paquete no implican tener un efecto inmediato en los otros equipos.

    • Cada equipo puede decidir por sí mismo cuándo adaptar sus paquetes a las nuevas versiones de los paquetes que utilizan.

¿Cómo?

Principios de Paquetes

Principios de Acoplamiento Principios de Cohesión
  • Principio de Dependencias Acíclicas

    • Acyclic Dependencies Principle (ADP)

  • Principio de Reutilización Común

    • Common Reuse Principle (CRP)

  • Principio de Dependencias Estables

    • Stable Dependencies Principle (SDP)

  • Principio de Cierre común

    • Common Closure Principle (CCP)

  • Principio de Abstracciones Estables

    • Stable Abstractions Principle (SAP)

  • Principio de Equivalencia de Liberación / Reutilización

    • Release/Reuse Equivalency Principle (ERP)

Principios de Acoplamiento

Dependencia y Acoplamiento de Elementos

  • Una dependencia entre elementos es una asociación en la que el elemento origen precisa, requiere, necesita, …​depende de un elemento destino

    • Las dependencias entre elementos se pueden representar con un grafo:

      • los elementos son los nodos y

      • las dependencias son los arcos dirigidos

dependenciaElemento
Acoplamiento de un elemento Acoplamiento eferente de un elemento Acoplamiento aferente de un elemento

es el conjunto de dependencias en las que el elemento es el elemento origen o destino

es el conjunto de dependencias en las que el elemento es el elemento origen

es el conjunto de dependencias en las que el elemento es el elemento destino

elementos de los que depende el elemento dado o que dependen del elemento dado

elementos de los que depende el elemento dado

elementos que dependen del elemento dado

acoplamientoObjetos
acoplamientoObjetosEferente
acoplamientoObjetosAferente

los elementos relacionados desde arriba y hacia abajo, hacia afuera y hacia adentro, todos los elementos relacionados con el elemento dado

los elementos relacionados hacia abajo y hacia afuera del elemento dado

los elementos relacionados desde arriba y hacia adentro del elemento dado

|A| >= 0

|Ae| >= 0

|Aa| >= 0

Dependencias y Acoplamiento de Clases

  • Una dependencia entre clases es una asociación en la que la clase origen hereda, tiene, está asociada, usa o depende de la clase destino

    • Una prueba de unidad de una clase requiere compilar y enlazar con las clases de las que depende

    • Las dependencias entre clases se pueden representar con un grafo:

      • las clases son los nodos y

      • las dependencias son los arcos dirigidos

dependenciaClase
Acoplamiento de una clase Acoplamiento eferente de una clase Acoplamiento aferente de una clase

es el conjunto de dependencias en las que la clase es el elemento origen o destino

es el conjunto de dependencias en las que la clase es el elemento origen

es el conjunto de dependencias en las que la clase es el elemento destino

clases de los que depende la clase dada o que dependen de la clase dada

clases de los que depende la clase dada,

clases que dependen de la clase dada

clases base y derivadas, todo y partes, asociadas y usadas por y a la clase

clases base, parte, asociadas y que son usadas por la clase dada

clases derivadas, todo, asociadas y que usan a la clase dada

acoplamientoClasesTopDown
acoplamientoClasesEferenteTopDown
acoplamientoClasesAferenteTopDown
acoplamientoClases
acoplamientoClasesEferente
acoplamientoClasesAferente

|A| >= 0

|Ae| >= 0

|Aa| >= 0

Dependencia y Acoplamiento de Paquetes

  • Una relación de dependencia entre paquetes es una asociación en la que el paquete origen tiene una clase con alguna dependencia hacia alguna clase del paquete destino

    • Una prueba de componente/integración de un paquete requiere compilar y enlazar con los paquetes de los que depende

    • Las dependencias entre paquetes se pueden representar con un grafo:

      • los paquetes son los nodos y

      • las dependencias son los arcos dirigidos

dependenciaPaquete
Acoplamiento de un paquete Acoplamiento eferente de un paquete Acoplamiento aferente de un paquete

es el conjunto de dependencias en las que el paquete es el elemento origen o destino

es el conjunto de dependencias en las que el paquete es el elemento origen

es el conjunto de dependencias en las que el paquete es el elemento destino

paquetes de los que depende el paquete dado o que dependen del paquete dado

paquetes de los que depende el paquete dado

paquetes que dependen del paquete dado

acoplamientoPaquetes
acoplamientoPaquetesEferente
acoplamientoPaquetesAferente

los paquetes relacionados desde arriba y hacia abajo, hacia afuera y hacia adentro, todos los elementos relacionados con el paquete dado

los paquetes relacionados hacia abajo y hacia afuera del paquete dado

los paquetes relacionados desde arriba y hacia adentro del paquete dado

|A| >= 0

|Ae| >= 0

|Aa| >= 0

Ejemplo sin ciclos Ejemplo con ciclos
sinCiclos
conCiclos
  • Acoplamiento Eferente del paquete "D"

    • el paquete "D" depende directamente de los paquetes "E", "F" y "G"

      • el paquete "G" depende directamente del paquete "H"

    • el paquete "D" depende, directa o indirectamente, de los paquetes "E", "F", "G" y "H"

    • 4 de 8 paquetes

    • 50% del sistema

  • Acoplamiento Eferente del paquete "D"

    • el paquete "D" depende directamente de los paquetes "E", "F" y "G"

      • el paquete "G" depende directamente de los paquetes "H" y "A"

        • el paquete "A" depende directamente de los paquetes "B", "C" y "D"

          • el paquete "B" depende directamente del paquete "H"

          • el paquete "C" depende directamente del paquete "H" y "E"

    • el paquete "D" depende, directa o indirectamente, de los paquetes "A", "B", "C","D", "E", "F", "G" y "H"

    • 8 de 8 paquetes

    • 100% del sistema

  • Prueba de componente/integración del paquete "D" requiere compilar y enlazar con las versiones entregadas de los paquetes eferentes

    • paquetes "E", "F", "G" y "H"

    • 4 de 8 paquetes

    • 50% del sistema

  • Prueba de componente/integración del paquete "D" requiere compilar y enlazar con las versiones entregadas de los paquetes eferentes

    • paquetes "A", "B", "C", "D", "E", "F", "G" y "H"

    • 8 de 8 paquetes

    • 100% del sistema

  • Acoplamiento Aferente del paquete "D"

    • del paquete "D", depende directamente el paquete "A"

    • el paquete "A" depende directa o inderectamente del paquete "D"

    • 1 de 8 paquetes

    • 12,5% del sistema

  • Acoplamiento Aferente del paquete "D"

    • del paquete "D", depende directamente el paquete "A"

      • del paquete "A", depende directamente el paquete "G"

    • los paquetes "A" y "G" dependen, directa o indirectamente, del paquete "D"

    • 2 de 8 paquetes

    • 25% del sistema

  • _Nueva versión del paquete "D" requiere re-compilar y re-enlazar con los paquetes aferentes _

    • paquete [green]"A"_

    • 1 de 8 paquetes

    • 12,5 del sistema

  • Nueva versión del paquete "D" requiere re-compilar y re-enlazar con los paquetes aferentes

    • paquetes "A", "B", "C", "D", "E", "F", "G" y "H"

    • 8 de 8 paquetes

    • 100% del sistema

  • Nueva versión del sistema requiere re-compilar, re-probar y re-entregar de abajo hacia arriba

    • paquetes “H”, "E" y "F" en paralelo independientemente;

    • paquetes “B”, "C" y "G" en paralelo independientemente;

    • paquete "D";

    • paquete "A"

  • Nueva versión del sistema requiere re-compilar, re-probar y re-entregar

    • paquetes “H”, "E" y "F" en paralelo independientemente;

    • paquetes “B” y "C" en paralelo independientemente;

    • paquetes "A", “D" y "G" al mismo tiempo;

  • Fácil

    • Pruebas de un paquete requiere versiones de los paquetes que forman parte del acoplamiento eferente del paquete, limitándose a un subconjunto de todo el sistema

    • Nueva versión de un paquete impacta en los paquetes que forman parte del acoplamiento aferente del paquete, limitándose a un subconjunto de todo el sistema

  • Difícil

    • Pruebas de paquete requiere versiones de los paquetes que forman parte del acoplamiento eferente del paquete, pudiendo alcanzar a todo el sistema, se ha convertido en un “paquete grande”

    • Nueva versión de un paquete impacta en los paquetes que forman parte del acoplamiento aferente del paquete, pudiendo alcanzar a todo el sistema, se ha convertido en un “paquete grande”

Principio de Dependencias Acíclicas

  • Los ciclos hacen que sea muy difícil aislar módulos, realizar pruebas de unidad y entregas con ausencia de errores

  • En proyectos

    • pequeños, con unos pocos desarrolladores, no es un problema demasiado grande.

    • medianos/grandes, cuando crece el tamaño del equipo de desarrollo, es un problema demasiado grande:

      • no es raro que pasen las semanas sin ser capaces de construir una versión estable del proyecto.

      • todo el equipo está cambiando perpetuamente su código tratando de hacer que funcione con los últimos cambios que otra persona hizo.

La estructura de dependencias entre los paquetes debe ser un grafo dirigido acíclico. Es decir, no debe haber ciclos en la estructura de dependencias.
— Robert C. "Uncle Bob" Martin
Clean Architecture. A Craftman's Guide to Software Structured and Design
Mecanismo para romper ciclos entre paquetes Ggrafo dirigido acíclico de dependencias
  • Aplicar el Principio de Inversión de Dependencias (DIP).

    • Crear una interfaz "Z" en el paquete "g"

      • que tiene los métodos que necesita la clase "Y" del paquete “g” y

      • que es implementada por la clase "X" del paquete “a”.

    • Esto invierte la dependencia entre “g” y “a” rompiendo el ciclo.

sinCiclosDIP
  • Aplicar un nuevo reparto de responsabilidades entre paquetes con un nuevo paquete alojando la(s) clase(s) de los paquetes que provocaron el ciclo y éstos paquetes dependen del nuevo paquete

    • Crear un paquete "i" con la clase "X"

      • de la que dependen las clases de los paquetes "a" y "g"

    • Esto invierte la dependencia entre “g” y “a” rompiendo el ciclo.

sinCiclosPaquete

Principio de Dependencias Estables

Volatilidad Estabilidad
  • La volatilidad de un módulo es la probabilidad de que cambie con su consecuente mantenimiento. Cuando los destinos de las dependencias son extremadamente improbable que cambien, no son volátiles.

    • las dependencias de un módulo

      • con baja volatilidad, es mejor

      • con alta volatilidad, es peor

    • es difícil de predecir porque depende de todo tipo de factores:

      • presiones del mercado,

      • de los caprichos de los clientes,

      • …​

      • algo que un cliente va a querer cambiar.

  • La estabilidad de un módulo es un factor que influye en la volatilidad y muy fácil de medir. Entonces, los módulos más inestables, más difíciles de cambiar, deben ser los menos volátiles

    • La definición clásica de la palabra "estabilidad" es "no se puede mover fácilmente".

    • La estabilidad

      • es una medida de la dificultad en el cambio del módulo

      • no es una medida de la probabilidad de que un módulo cambie.

  • Un diseño orientado a objetos fiable, flexible y reutilizable es por su falta de interdependencias. Sin embargo, tiene algunas dependencias pero esas dependencias no tienen por qué interferir en esas cualidades deseables.

  • Métrica de inestabilidad de un paquete, no repercusión,:

    • I = |Ae| / (|Ae| + |Aa|).

      • donde:

        • |Ae|>=0, siendo Ae el acoplamiento eferente;

        • |Aa|>=0, siendo Aa el acoplamiento eferente;

        • 0 ⇐ I ⇐ 1, siendo I la inestabilidad del paquete

valorInestabilidad

Estudio de valores extremos de la Inestabilidad

  • Para I = 0:

    • se obtiene un mínimo de inestabilidad y

    • un máximo de estabilidad del paquete porque con

      • Ae = 0

        • no depende de clases de fuera, sino que

        • los demás paquetes dependerán de él. Él no depende de nadie.

  • Para I = 1:

    • se obtiene un máximo de inestabilidad y

    • un mínimo de estabilidad del paquete porque con

      • Aa = 0

        • los demás paquetes no dependen de sus clases, sino que

        • sus clases dependerán de otras de otros paquetes. Un cambio en el paquete no repercutirá en otros paquetes.

  • cambios en el paquete repercutirán a otros paquetes, es responsable de los demás.

  • cambios en el paquete no repercutirán a otros paquetes, es irresponsable de los demás.

  • cambios en otros paquetes no repercutirán al paquete, es independiente de los demás.

  • cambios en otros paquetes repercutirán al paquete, es dependiente de los demás.

Estable

Intermedio

Inestable

responsable
iyresponsable
irresponsable
  • I = |Ae| / (|Ae| + |Aa|)

    • I = 0 / (0 + 3) = 0/3 = 0

  • I = |Ae| / (|Ae| + |Aa|)

    • I = 3 / (3 + 3) = 3/6 = 0,5

  • I = |Ae| / (|Ae| + |Aa|)

    • I = 3 / (3 + 0) = 3/3 = 1

Responsable

Intermedio

Irresponsable

Independiente

Intermedio

Dependiente

Hoja

Intermedio

Raíz

Las dependencias entre paquetes en un diseño deben estar en la dirección de la estabilidad de los paquetes. Un paquete debe depender sólo de paquetes más estables
— Robert C. "Uncle Bob" Martin
Clean Architecture. A Craftman's Guide to Software Structured and Design
estabilidadBien
estabilidadMal

Principio de Abstracciones Estables

  • Métrica de abstracción de un paquete:

    • A = |Ca| / |Ct|.

      • Donde

        • |Ca|>=0, siendo Ca el número de clases abstractas;

        • |Aa|>=0, siendo Aa el número total de clases;

        • 0 ⇐ A ⇐ 1, siendo A la abstracción deL paquete

Mínima abstracción Máxima abstracción
  • A = 0

  • A = 1

  • se obtiene un mínimo de abstracción, máxima concreción

  • se obtiene un máximo de abstracción, mínima concreción

  • no es extensible en cuanto que para añadir funcionalidad habrá que, en algún momento, modificar el diseño de las clases que no pueden asumir un crecimiento ilimitado con nuevas funcionalidades

  • es extensible en cuanto que para añadir funcionalidad habrá que añadir otros paquetes con clases instanciables que hereden de las clases abstractas de forma ilimitada

Relación entre Estabilidad y Abstracción
Análisis de combinaciones de valores extremos Análisis de combinaciones de valores intermedios
  • E=1 y A=1:

    • paquetes máximamente estables, difíciles de modificar, y

    • máximamente abstractos, fáciles de extender, permiten añadir funcionalidad sin repercutir en el diseño global del sistema

  • E=1 y A=0:

    • paquetes máximamente estables, difíciles de modificar, y

    • máximamente concretos, difíciles de extender, no permiten añadir funcionalidad sin repercutir en el diseño global del sistema

  • Paquetes tienen grados de abstracción y la estabilidad.

    • Para una clase: es muy común que una clase abstracta deriva de otra clase abstracta; la derivada es una abstracción que tiene una dependencia eferente, lo que disminuye su estabilidad; por tanto, aunque es máximamente abstracta, no será máximamente estable.

    • Para un paquete: con más razón en cuanto que la abstracción no será extrema en cuanto contenga clases abstractas y concretas en cualquier número

  • E=0 y A=0:

    • paquetes máximamente inestables, fáciles de modificar, y

    • máximamente concretos, difíciles de extender, permiten añadir funcionalidad sin repercutir en el diseño global del sistema

  • E=0 y A=1:

    • paquetes máximamente inestables, fáciles de modificar, y

    • máximamente abstractos, fáciles de extender, no tienen sentido porque serían un conjunto de clases abstractas sin dependencias aferentes, sin ninguna derivada

Malas: Buenas:
  • E~1 y A~0: paquetes muy estables, difíciles de modificar, y muy concretos, difíciles de extender:

    • paquete de utilidades con cadenas de caracteres, … pero no repercute por su ínfima volatilidad.

    • paquete de interfaz entre las aplicaciones OO y las bases de datos relacionales que conlleva habituales quebraderos de cabeza por su volatilidad

  • E~0 y A~1: no tienen sentido

  • E=A en la secuencia principal: paquetes con el mismo grado de estabilidad y abstracción porque el grado de dificultad de cambio está acompasado con su grado de extensibilidad. Tiene el número "correcto" de clases concretas y abstractas en proporción a su dependencias eferentes y aferentes

Los paquetes con máxima estabilidad deben ser máximamente abstractos. Los paquetes inestables deberían ser concretos. La abstracción de un paquete debe estar en proporción a su estabilidad
— Robert C. "Uncle Bob" Martin
Clean Architecture. A Craftman's Guide to Software Structured and Design

secuenciaPrincipal

  • Distancia de un paquete a las secuencia principal:

    • D = | (A + E) / √2 | con valores entre [0, ~ 0,707]

    • D’ =| (A + E) | con valores entre [0, 1]

      • Para D‘~ 0 son paquetes más reutilizables y menos sensible a los cambios

      • Para D‘~ 1 son paquetes que deben ser re-examinados y reestructurados.

      • La bondad del diseño global se obtiene con una media y una varianza de todas las D’ cerca de cero.

inestabilidadOpenClose1
inestabilidadOpenClose2
inestabilidadOpenClose3
  • Principio Open/Close

    • Paquetes de interfaces permiten la extensión de funcionalidades sin afectar a sus clientes mediante el Principio de Inversión de Dependencias

Principios de Cohesión

  • Determinan qué clases colocar dentro de los paquetes adecuados

Principio de Reusabilidad Común

  • Las clases rara son vez reusadas de manera aislada, colaboran con otras clases que forman parte de la abstracción reusable.

    • Un ejemplo sería una clase contenedora y sus iteradores asociados. Estas clases son reusadas juntas porque están estrechamente acopladas entre sí.

  • La razón por la que estas clases van juntas en el mismo paquete es que cuando un ingeniero decide utilizar un paquete se crea una dependencia con todo el paquete. A partir de entonces, cada vez que el paquete es versionado, las aplicaciones que lo utilizan deben ser revalidadas y re-versionadas.

    • Si un paquete está siendo versionado a causa de los cambios en una clase que no afecta, entonces no será muy agradable tener que re-validar y re-versionar la aplicación

Las clases de un paquete se reutilizan juntas. Si se reusa una de las clases de un paquete, se reusan todas
— Robert C. "Uncle Bob" Martin
Clean Architecture. A Craftman's Guide to Software Structured and Design

Principio de Cierre Común

  • Más importante que la reusabilidad, es el mantenimiento

  • Este principio está estrechamente asociado con el Principio Abierto/Cerrado (OCP). El OCP afirma que las clases deben estar cerradas para la modificación pero abiertas para la extensión. Los sistemas se diseñan de tal forma que la están cerrados para los tipos de cambios más probables que prevemos. El 100% del cierre no es alcanzable pero debe ser la estratégica.

    • El "cierre" es en el sentido de la palabra de OCP. Si dos clases están tan estrechamente vinculadas, de tal manera que casi siempre se cambian juntas, deben pertenecer al mismo paquete. Esto reduce al mínimo la carga de trabajo relacionada con el versionado, revalidación y redistribución del software.

    • Parece claro que se prefiere que los cambios se centren en un solo paquete en lugar de tener que excavar a través de un montón de paquetes y cambiar a todos. De esa manera sólo necesitamos versionar el paquete modificado. Otros paquetes que no dependen del paquete modificado no tienen que ser revalidados o reversionados de nuevo. Por lo tanto, cuando se presente un cambio de requisitos, que el cambio tenga una buena oportunidad de ser restringido a un número mínimo de paquetes.

Las clases de un paquete deberían encerrarse juntas contra la misma clase de cambios. Un cambio que afecta a un paquete, afecta a todas las clases del paquete
— Robert C. "Uncle Bob" Martin
Clean Architecture. A Craftman's Guide to Software Structured and Design

Principio de Equivalencia entre Reusabilidad y Entregable

  • Se reusa código, si y sólo si, nunca se necesita mirar el código fuente, que no sean sus partes públicas. Es decir, se espera que el código que se está reusando sea tratado como un producto.

    • No se mantiene en el desarrollo de la aplicación ni se distribuye.

    • El autor es el responsable de su mantenimiento y distribución.

      • Siempre que las bibliotecas son arregladas o mejoradas, se recibe una nueva versión que se puede integrar en el sistema cuando la oportunidad lo permita.

  • La granularidad de la reusabilidad no puede ser menor que la granularidad de los entregables.

    • Puede que sea posible entregar y llevar el control de versiones de clases pero hay tantas clases en una aplicación típica que esto casi seguro que abruma al sistema de control de versiones.

    • Se necesita una entidad de mayor escala para actuar como granulo para los entregables y, claramente, el paquete es el candidato para dicha granularidad.

La granularidad de la reusabilidad es la granularidad del entregable. Sólo los componentes que se entregan mediante un sistema de control de versiones pueden ser efectivamente reusados. Esta *granularidad es el paquete.
— Robert C. "Uncle Bob" Martin
Clean Architecture. A Craftman's Guide to Software Structured and Design

Resumen

Principios de Acoplamiento Principios de Cohesión
  • Principio de Dependencias Acíclicas: la estructura de dependencias entre los paquetes debe ser un grafo dirigido acíclico. Es decir, no debe haber ciclos en la estructura de dependencias

  • Principio de Reutilización Común: las clases de un paquete se reutilizan juntas. Si se reusa una de las clases de un paquete, se reusan todas

  • Principio de Dependencias Estables: las dependencias entre paquetes en un diseño deben estar en la dirección de la estabilidad de los paquetes. Un paquete debe depender sólo de paquetes más estables

  • Principio de Cierre común: las clases de un paquete deberían encerrarse juntas contra la misma clase de cambios. Un cambio que afecta a un paquete, afecta a todas las clases del paquete

  • Principio de Abstracciones Estables: los paquetes con máxima estabilidad deben ser máximamente abstractos. Los paquetes inestables deberían ser concretos. La abstracción de un paquete debe estar en proporción a su estabilidad

  • Principio de Equivalencia de Liberación / Reutilización: la granularidad de la reusabilidad es la granularidad del entregable. Sólo los componentes que se entregan mediante un sistema de control de versiones pueden ser efectivamente reusados. Esta granularidad es el paquete

Actores y Atributos de la Arquitectura

Actor Responsabilidad

Usuarios

colaborando con UX y desarrolladores

Desarrolladores

implementan el producto, las pruebas funcionales y no funcionales (distribución, pruebas de carga, de estabilidad…​) en diferentes entornos (testing, pre-producción, producción)

Gestores de proyectos

planifican el equipo, solicitan recursos , toman decisiones sobre el personal asignado al proyecto, funcionalidades del sistema y requisitos no funcionales

Administradores

preparan la infraestructura del entorno, despliegan el sistema, recogen los logs, monitorizan el sistema, escalan según necesidades y mantienen la infraestructura

Analista de Negocios

analiza los datos proporcionados por operaciones, buscan patrones en comportamientos y oportunidades de negocio y también son útiles para monitorizar (patrones en fallos)

Tipo Atributo Capacidad

Atributos de Calidad

Portabilidad

de plataforma, SSOO, dispositivos, Cloud, …​

Adaptabilidad al cambio

capacidad de añadir nueva funcionalidad

Comprensible

el software es entendible por quien debe efectuar los cambios

Testabilidad

pueden construirse tests para las nuevas funcionalidades

Usabilidad (UX)

los usuarios pueden usarlo de forma eficiente y satisfactoria

Seguridad

prevenir accesos no autorizados

Integridad de datos

evitar la corrupción de datos por su desactualización

Atributos de Operación

Disponibilidad

porcentaje del tiempo que el sistema está disponible

Actualización

capacidad de actualizar el sistema en funcionamiento (en caliente)

Fiabilidad

capacidad del sistema de operar durante largos periodos de tiempo

Recuperabilidad

tiempo necesario para recuperar el sistema cuando se producen fallos

Capacidad de gestión

capacidad de gestionar e inspeccionar sus componentes

Atributos de Rendimiento

Tiempo de respuesta

de los distintos casos de uso que ofrece el sistema

Elasticidad

capacidad del sistema para aumentar o disminuir su capacidad en función de la carga

Capacidad (throughput)

capacidad de soportar cargas extremas sin dejar de dar servicio

Documentación de la Arquitectura

4+1 Vistas

krutchen

Diagramas5
Vistas Contenidos Diagramas Arquitectura

Casos de Uso

Incluye casos de uso que describe el comportamiento como es visto por los usuarios, analistas y probadores

  • Diagramas de Casos de Uso

  • Diagramas de Estados para el Contexto de los Casos de Uso

  • Diagramas de Estados, Actividad o Secuencia para la Especificación de Casos de Uso

Requisitos de la Arquitectura del Sistema Informático

Lógica o Diseño

Incluye clases, interfaces y colaboraciones que forman el vocabulario del problema y su solución (tratando con los requisitos funcionales)

  • Diagramas de Paquetes para la Arquitectura

  • Diagramas de Clase y Objetos para cada Paquete

  • Diagramas de Colaboración y Secuencia para Mecanismos

Arquitectura del Software

Desarrollo o Implementación

Incluye componentes usados para ensamblar y hacer posible el sistema físico (la gestión de configuración de versiones consiste de los componentes que pueden ser ensamblados de varias formas para dar un ejecutable)

  • Diagramas de Componentes

Arquitectura del Sistema

Física o Despliegue

Incluye nodos que forman la topología hardware sobre la que el sistema se ejecuta (cubriendo distribución, entrega e instalación)

  • Diagramas de Despliegue

Arquitectura de Sistema

Procesos

Incluye los hilos y/o procesos que forman los mecanismos de concurrencia y sincronización del sistema (operaciones, adaptabilidad y rendimiento del sistema)

  • Diagramas de Actividad con calles (swinlanes) para cada hilo de ejecución

Arquitectura de Software y/o Sistema

Estilos Arquitectónicos

  • Movimientos en la arquitectura civil.

    • Edad de Bronce / Egipcio (Imhotep)

    • Griego / Romano (Vitruvio)

    • Bizantino / románico

    • Gótico

    • Manierismo (Miguel Ángel, Palladio)

    • Barroco

    • Ingeniería / Racional / Nacional / Romántico

    • Art Nouveau

    • Modernismo (Wright, LeCorbusier)

Un estilo arquitectónico, con un nombre bien definido, es una colección de decisiones de diseño arquitectónico que (1) son aplicables en un contexto de desarrollo dado, (2) restringen decisiones de diseño arquitectónico que son específicas para un sistema particular dentro de ese contexto, y (3) obtienen cualidades beneficiosas en cada sistema resultante."
— Software Architecture Foundations
Theory and Practice
Un estilo arquitectónico define una familia de sistemas en términos de un patrón de organización estructural. Un estilo arquitectónico define, un vocabulario de componentes y tipos de conectores, un conjunto de restricciones sobre cómo se pueden combinar, uno o más modelos semánticos que especifican cómo se pueden determinar las propiedades generales de un sistema a partir de las propiedades de sus partes
— Booch
  • Los términos "estilo arquitectónico", "patrón arquitectónico" y "lenguaje arquitectónico" se usan a menudo con un significado similar.

    • Los patrones arquitectónicos se refieren a patrones en el nivel del sistema.

    • Los patrones de diseño son más pequeños en escala y capturan el conocimiento de diseño sobre componentes a nivel de subsistema.

  • Los patrones de arquitectura y diseño son independientes de los lenguajes de programación. La codificación de los patrones describen sugerencias exitosas para la realización de patrones de diseño o problemas de codificación típicos en un lenguaje de programación específico.

Niveles de abstracción Descripción

Estilo arquitectónico / Patrón arquitectónico

  • Define los tipos de elementos y cómo interactúan.

  • A veces define una correspondencia entre funcionalidades y ciertos elementos arquitectónicos.

Arquitectura de referencia / Dominio Específico

  • Define los tipos de elementos y cómo interactúan.

  • Se aplican a un dominio particular

  • Definen cómo se asigna la funcionalidad del dominio a los elementos arquitectónicos.

Arquitectura de línea de producto

  • Se aplica a un conjunto de productos dentro de una empresa.

  • Define los tipos de elementos, cómo interactúan, cómo se asigna la funcionalidad del producto.

  • También puede definir algunas de las instancias de los elementos arquitectónicos. Por ejemplo, los componentes de informe de errores serían comunes a muchos productos de la línea de productos

Arquitectura de software

  • Se aplica a un sistema

  • Describe los tipos de elementos, cómo interactúan, cómo se asigna la funcionalidad del producto.

  • Describe las instancias que existen en el sistema.

  • Nivel de especificidad necesario para diseñar un sistema.

Término

Define los tipos de elementos y cómo interactúan.

Define el mapeo de la funcionalidad a los elementos de la arquitectura.

Define instancias de elementos de arquitectura

Un estilo arquitectónico

si

a veces

no

Una arquitectura de referencia

si

si

no

Una arquitectura de línea de productos

si

si

a veces

Una arquitectura de software

si

si

si

Arquitecturas Estructurales

Arquitecturas de Capas

A menudo hay confusion entre los términos de capa lógica (layer) y física (tier), siendo usadas como sinónimos. La mayoría de la gente ve capa física implicando una separación física. Los sistemas cliente/servidor a menudo se describen como dos capas físicas y la separación es física: el cliente es un escritorio y el servidor es un servidor. Yo uso capa lógica para reforzar que tú no tienes que ejecutar las capas lógicas en diferentes máquinas. Una capa lógica de la lógica del dominio a menudo corre tanto en un escritorio como en un servidor de bases de datos. En esta situación tienes dos nodos pero tres capas lógicas. Con una base de datos local puedo ejecutar las tres capas lógicas en un solo portatil pero todavía serán tres capas lógicas distintas
— Fowler
Architectural Patterns
  • El patrón arquitectónico de capas ayuda a estructurar aplicaciones que se pueden descomponer en grupos de subtareas en las que cada grupo de subtareas se encuentra en un nivel particular de abstracción

  • Comience en el nivel más bajo de abstracción, llámelo Capa 1.

    • Esta es la base de su sistema.

    • Ábrete paso hacia arriba en la escalera de abstracción colocando la Capa J sobre la Capa J - 1 hasta que alcances el nivel superior de funcionalidad, llámala Capa N

capa
arquitectruaCapas
  • El patrón de capas describe el principio más extendido de la subdivisión arquitectónica.

    • Muchos de los diagramas de bloques que vemos en los documentos de la arquitectura del sistema parecen implicar una arquitectura en capas.

    • Sin embargo, las arquitecturas reales con demasiada frecuencia resultan ser una mezcla de paradigmas diferentes que, por sí solos, no pueden ser criticados, u ocultan colecciones de componentes que cooperan sin límites arquitectónicos claros entre ellos.

  • Los protocolos de red son probablemente el ejemplo más conocido de arquitecturas en capas.

  • Dicho protocolo consiste en un conjunto de reglas y convenciones que describen cómo los programas informáticos se comunican a través de los límites de la máquina.

  • Se definen el formato, los contenidos y el significado de todos los mensajes.

  • Todos los escenarios se describen en detalle, generalmente dando diagramas de secuencia.

  • El protocolo especifica acuerdos en una variedad de niveles de abstracción, desde los detalles de la transmisión de bits hasta la lógica de la aplicación de alto nivel.

  • Por lo tanto, los diseñadores usan varios subprotocolos y los organizan en capas.

  • Cada capa se ocupa de un aspecto específico de la comunicación y utiliza los servicios de la siguiente capa inferior.

  • La Organización Internacional de Normalización (ISO) definió el siguiente modelo arquitectónico, el Modelo OSI de 7 capas

osi

Tuberías y Filtros (Pipes and Filters)

  • Proporciona una estructura para sistemas que procesan un flujo de datos.

    • Divide la tarea de un sistema en varios pasos de procesamiento secuencial.

    • Los datos de salida de un paso son la entrada al paso siguiente.

    • Cada paso de procesamiento es implementado por un componente de filtro.

filtrosTuberias
  • Un filtro consume y entrega datos de manera incremental, en contraste con el consumo de toda su entrada antes de producir cualquier salida, para lograr una baja latencia y permitir el procesamiento paralelo real.

    • La entrada al sistema es proporcionada por una fuente de datos como un archivo de texto.

    • La salida fluye a un receptor de datos, como un archivo, terminal, programa de animación, etc.

  • La fuente de datos, los filtros y el sumidero de datos están conectados secuencialmente por tuberías adyacentes.

  • Cada tubería implementa el flujo de datos entre los pasos de procesamiento adyacentes.

  • La secuencia de filtros combinados por tuberías se denomina tubería de procesamiento.

Escenario Diagrama
  • Escenario I.

    • Muestra un canal de inserción en el que la actividad comienza con la fuente de datos.

    • La actividad del filtro se activa al escribir datos en los filtros pasivos

escenario1

  • Escenario II.

    • Muestra una tubería de tracción.

    • Aquí el flujo de control se inicia cuando el receptor de datos solicita datos.

escenario2

  • Escenario III.

    • Muestra una tubería mixta push-pull con fuente de datos pasiva y sumidero.

    • Aquí el segundo filtro desempeña el papel activo y comienza el procesamiento.

escenario3

  • Escenario IV.

    • Muestra un comportamiento más complejo pero típico de un sistema de tuberías y filtros.

    • Todos los filtros tiran y empujan los datos en un bucle.

    • Por lo tanto, cada filtro se ejecuta en su propio hilo de control, por ejemplo, como un proceso separado.

    • Los filtros están sincronizados por una tubería de búfer entre ellos.

    • Para simplificar, asumimos que la tubería solo amortigua un solo valor.

escenario4

  • Conceptualmente, la traducción del lenguaje de programación de alto nivel al código de máquina consta de las fases de análisis léxico, análisis de sintaxis, análisis semántico, generación de código intermedio y, opcionalmente, optimización de código intermedio.

    • Cada etapa tiene datos de entrada y salida bien definidos.

    • La entrada al proceso de compilación es una secuencia de caracteres ASCII que representan el lenguaje de programación de alto nivel.

    • La etapa final en nuestro sistema, ya sea backend o intérprete, toma el código binario como su entrada

compilador

Arquitecturas de Persistencia

  • Registro Activo (Active Record)

    • Un objeto cubre una fila de una tabla o vista de base de datos, encapsula el acceso a la base de datos y agrega lógica de dominio a esos datos.

    • Patrón de Experto en la Información para la distribución de responsabilidades

    • Diseño modular

registroActivo
  • Puerta de enlace a Fila de Datos (Row Data Gateway)

    • Un objeto que actúa como una puerta de enlace a los objetos de una fuente de datos.

    • Principio Abierto/Cerrado y Sustitución de Liskov para búsquedas extensibles

    • Diseño modular

enlaceFila
  • Puerta de enlace a Tabla de Datos (Table Data Gateway) / Objeto de Acceso a Datos (Data Access Object)

    • Un objeto que actúa como una puerta de enlace a una tabla de base de datos. Una instancia maneja todas las filas en la tabla.

    • Principio Abierto/Cerrado y Sustitución de Liskov para tecnologías extensibles

    • Diseño modular

enlaceTabla
  • Asociador de Datos (Data Mapper) Asociador Objeto/Relacional (Object-Relation Mapper, ORM)

Arquitecturas Adaptables

Arquitectura de Micronúcleo (microkernel)

  • Los Sistemas operativos se caracterizan por disponer de un núcleo (no monolíticos) que implementa únicamente: la planificación de procesos, mecanismo de comunicación entre procesos y gestión de interrupciones.

  • Además, existen procesos servidores que se ejecutan en modo no privilegiado del procesador -que, por supuesto, se ejecutan fuera del espacio del núcleo del sistema operativo- y que implementan: la administración de memoria principal, la administración de ficheros y la gestión de dispositivos de entrada/salida.

  • El patrón arquitectónico de Microkernel se aplica a los sistemas de software que deben poder adaptarse a los requisitos cambiantes del sistema.

    • Separa un núcleo funcional mínimo de la funcionalidad extendida y las partes específicas del cliente.

    • El microkernel también sirve como un zócalo para conectar estas extensiones y coordinar su colaboración.

Componente Responsabilidad

Microkernel

  • El microkernel representa el componente principal del patrón. Implementa servicios centrales como facilidades de comunicación o manejo de recursos.

    • Otros componentes se basan en todos o algunos de estos servicios básicos.

    • Muchas dependencias específicas del sistema están encapsuladas dentro del microkernel. Por ejemplo, la mayoría de las partes dependientes del hardware están ocultas para otros participantes.

    • Un microkernel implementa servicios atómicos, a los que nos referimos como mecanismos. Estos mecanismos sirven como una base fundamental sobre la cual se construyen funcionalidades más complejas, llamadas políticas.

Servidor interno

  • un servidor interno, también conocido como un subsistema, extiende la funcionalidad proporcionada por el microkernel. Representa un componente separado que ofrece funcionalidad adicional.

    • El microkernel invoca la funcionalidad de los servidores internos a través de solicitudes de servicio. Por lo tanto, los servidores internos pueden encapsular algunas dependencias en el sistema de software o hardware subyacente. Por ejemplo, los controladores de dispositivos que admiten tarjetas gráficas específicas son buenos candidatos para servidores internos.

    • Puede considerar los servidores internos como extensiones del microkernel de patrones arquitectónicos.

Servidor externo

  • un servidor externo, también conocido como personalidad, es un componente que utiliza el microkernel para implementar su propia vista del dominio de aplicación subyacente. Como ya se mencionó,una vista denota una capa de abstracción construida sobre los servicios atómicos proporcionados por el microkernel. Diferentes servidores externos implementan diferentes políticas para dominios de aplicación específicos.

    • Los servidores externos exponen su funcionalidad al exportar interfaces de la misma manera que lo hace el propio microkernel. Cada uno de estos servidores externos se ejecuta en un proceso separado. Recibe solicitudes de servicio de las aplicaciones cliente utilizando las facilidades de comunicación proporcionadas por el microkernel, interpreta estas solicitudes, ejecuta los servicios apropiados y devuelve los resultados a sus clientes.

Cliente

  • Un cliente es una aplicación que está asociada con exactamente un servidor externo. Solo accede a las interfaces de programación proporcionadas por el servidor externo.

Adaptador

  • Los adaptadores, también conocidos como emuladores, representan estas interfaces entre los clientes y sus servidores externos, y les permiten a los clientes acceder a los servicios de su servidor externo de manera portátil. Son parte del espacio de direcciones del cliente.

    • Por lo tanto, introducimos interfaces entre los clientes y sus servidores externos para proteger a los clientes de las dependencias directas.

    • Si el servidor externo implementa una plataforma de aplicación existente, el adaptador correspondiente imita las interfaces de programación de esa plataforma. Los clientes escritos para la plataforma emulada pueden, por lo tanto, compilarse y ejecutarse sin modificaciones. Los adaptadores también protegen a los clientes de los detalles de implementación específicos del microkernel.

microkernel

Arquitecturas de Interacción

  • Vista Separada (Separated Presentation Pattern): Asegura que cualquier código que manipula la presentación solo manipula la presentación despalazando toda la lógica del dominio y de datos en áreas separadas del programa.

    • Sub-patron del Principio de Única Responsabilidad de SOLID que ayuda a definir capas lógicas y físicas de la arquitectura

  • El resultado de su aplicación serán Vistas que se responsabilizan de:

    • Gestionar sus controles de interfaz: botones, listas, … paneles, diálogos, ..

    • Gestionar su Lógica: para manipular los controles de interfaz

    • Gestionar su Estado: referido a los datos actuales mostrados en la interfaz

    • Gestionar su Sincronización: coordinando su estado con el estado de los objetos de datos y de negocio en memoria y/o bbdd

Sintesis

sintesis

Bibliografía

Obra, Autor y Edición Portada Obra, Autor y Edición Portada
  • Patterns of Enterprise Application Architecture

    • Martin Fowler

    • Addison-Wesley; (2002)

PatternsOfEnterpriseApplicationArchitecture

  • Clean Architecture: A Craftsman’s Guide to Software Structure and Design

    • Robert C Martin

    • Prentice Hall; (2017)

CleanArchitecture

  • The Art of Software Architecture: Design Methods and Techniques

    • Stephen T. Albin

    • Wiley; (2003)

TheArtOfSoftwareArchitecture

  • Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives

    • Nick Rozanski, Eóin Woods

    • Addison-Wesley; (2011)

SoftwareSystemsArchitecture

  • Software Architecture in Practice

    • Len Bass, Paul Clements, Rick Kazman

    • Addison-Wesley; (2012)

SoftwareArchitectureInPractice

  • Pattern-oriented Software Architecture: A System of Patterns

    • Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad

    • Wiley (1996)

PatternOrientedSoftwareArchitecture

  • Documenting Software Architectures

    • Paul Clements, Felix Bachmann, Len Bass ..

    • (2001)

DocumentingSoftwareArchitectures

  • Integrating Software Architecture-Centric Methods into Extreme Programming

    • Robert L. Nord, James E. Tomayko, Rob Wojcik

    • (2004)

IntegratingSoftwareArchitectureCentricMethods

Ponente

  • Luis Fernández Muñoz

setillo

  • Doctor en Inteligencia Artificial por la UPM

  • Ingeniero en Informática por la UMA

  • Diplomado en Informática por la UPM

  • Profesor Titular de ETSISI de la UPM