Fundamentos de Arquitectura de Software

Jose Jan Pierre Sanchez Manosalva
12 min readDec 10, 2021

La arquitectura, más que un modelo es algo estructural. El concepto de arquitectura de software se refiere a la estructuración del sistema que, idealmente, se crea en etapas tempranas del desarrollo. Esta estructuración representa un diseño de alto nivel del sistema que tiene dos propósitos

  • satisfacer los atributos de calidad (desempeño, seguridad, modificabilidad)
  • servir como guía en el desarrollo.

El no crear este diseño desde etapas tempranas del desarrollo puede limitar severamente el que el producto final satisfaga las necesidades de los clientes. Además, el costo de las correcciones relacionadas con problemas en la arquitectura es muy elevado. Es así que la arquitectura de software juega un papel fundamental dentro del desarrollo.

Dificultades en el desarrollo de software

Esenciales

  1. Complejidad: Es cuando el problema a resolver es complejo por si mismo.
  2. Conformidad: El contexto del uso del software, y la adecuación al mismo.
  3. Tolerancia al cambio: Una vez terminado el software, ¿Qué tan fácil se podrá modificarse?.
  4. Invisibilidad: El software no tiene forma física, si no que esta representado en código, infraestructura, etc.

Accidentales

  1. Lenguaje de alto nivel: Las maquinas entiende solo lenguaje binario, los lenguajes de programación se abstraen de esto, construyendo lenguajes de “alto nivel” el cual es mas cercano al lenguaje humano, para una mayor facilidad de interacción y creación de este.
  2. Multiprocesamiento: Actualmente con la tecnología actual, nos permite tener varios proceso al unísono, esto no da la opción de tener mucho mejor feedback y sistemas muchos mas óptimos.
  3. Entornos de programación: Es el editor de código, que muchas veces traen herramientas que nos facilitan el trabajo a la hora de programar, ejemplo: visual studio code, atom, etc.

¿Cómo resolver las dificultades esenciales?

  1. No desarrollar: Si la solución a tu problema ya existe, consíguela! No es necesario reinventar la rueda si esta ya existe, toma esa solución mas pequeña y intégrala a tu solución grande.
  2. Prototipado rápido: Metodologías ágiles, obtener feedback lo antes posible de que si estamos resolviendo el problema correcto.
  3. Desarrollo evolutivo: Metodologías ágiles, obtener resultados pequeños e ir evolucionándolas.
  4. Grandes diseñadores: Son desarrolladores que sean capaces de abstraerse del problema puntual y entender un problema mas general, generando soluciones simples pero con calidad.

Roles en metodologías tradicionales y ágiles

Desarrollo Tradicional

  1. Experto del dominio: Experto en necesidades de los requerimientos
  2. Analista: Persona responsable a definir el problema y buscar la solución
  3. Sysadmin: Encargado de toda la operación del sistema
  4. Equipos de desarrollos: Desarrolladores encargados de asegurar la calidad del producto, se dividen en muchas áreas, QA, Tester, Desarrolladores, Arquitectos.
  5. Gestor de proyectos: Administrador general de todo el proceso de desarrollo

Metodologías Ágiles

  1. Partes interesadas/stakeholders: Terceros expertos en el área del producto.
  2. Dueño del producto: El cliente que conoce su producto y sabe sus problemas, el puede realizas las historias y determinar cual sería el mejor camino para priorizar por etapas soluciones.
  3. DevOps: Conecta el desarrollo y las operaciones de infraestructura
  4. Equipos de desarrollos: Desarrolladores encargados de asegurar la calidad del producto, los equipos son autogestionados para realizar ellos mismo dichas funciones.
  5. Facilitador: Administrador general del producto, generalmente se encuentra muy atento a los nuevos cambios del día al día ya que irá cambiando todo el tiempo.

La importancia de la comunicación — Ley de Conway

En 1968, Mel Conway publico un paper llamado: How Do Comittes Invent?, en el cual exploraba la relación entre la estructura organizacional de una empresa y el resultado del diseño de un sistema. Una frase, mencionada en el paper, se convirtió en lo que hoy conocemos como la ley de Conway o Conway’s Law. Esta dice:

Organizations wich design systems… are constrained to produce designs wich are copies of the communication structures of these organizations.

Esta frase dice que hay una relación directa entre la comunicación que ocurre dentro de una organización y el diseño de la arquitectura de sus sistemas.

Objetivos del arquitecto

El arquitecto tiene varias partes interesadas “stakeholders” el cual tiene que conectar esto requerimientos de cada stakeholders con la implementación del sistema.

Stakeholders involucrados con diferentes requerimientos:
• Cliente: Entrega a tiempo y que no rebase el presupuesto.
• Manager: Comunicación clara entre los equipos que participan en el desarrollo del sistema
• Dev: Que el desarrollo llevado acabo sea fácil de implementar y mantener
• Usuario: Disponibilidad del producto.
• QA: Fácil de probar.

El arquitecto de software debe gestionar los siguientes puntos para cada Stakeholder:
• Encontrar los riegos más altas que afecten en el desarrollo del sistema (Cliente)
• Modularización y flexibilidad del sistema que se está desarrollando (Manager)
• Modularidad, mantenibilidad y capacidad de cambio del software (Dev)
• Desisdir estrategias para la disponibilidad del sistema (Usuario)
• Que el sistema pueda ser modularizado y cada una destas partes pueda ser probado de forma fácil (QA).

La unión de estos requerimientos (funcionales / no funcionales) va a llevar al arquitecto a tomar decisiones que impactan directamente en el desarrollo del software.

Arquitectura y Metodología

Entender el problema

Requerimientos

Una vez que entendemos el espacio del problema y el espacio de la solución, vamos a entrar a analizar los requerimientos de nuestro sistema.

Requerimientos de producto
Los podemos dividir en tres (03):

• Capa de requerimientos de negocio, son reglas del negocio que alimentan los requerimientos del negocio.
• Capa de usuario, tienen que ver en cómo el usuario se desenvuelve usando el sistema, qué atributos del sistema se deben poner por encima de otros.
• Capa Funcional, se ven alimentados por requerimientos del sistema, ¿qué cosas tienen que pasar operativamente?
Esta capa se ve afectada por las restricciones que pueden afectar operativamente a lo funcional.

Requerimientos Significativos para la Arquitectura del Producto:

  • Requerimientos funcionales: (Funciones indispensables) Tienen que ver con las historias de usuarios, que hablan sobre específicamente lo que hace el sistema, por ejemplo que usuario ingrese al sistema.
    • Requerimientos no funcionales: (Atributos de calidad): son aquellos que agregan cualidades al sistema, por ejemplo que el ingreso de ese usuario sea de manera segura.

Un requisito funcional describe lo que debe hacer un sistema de software, mientras que los requisitos no funcionales imponen restricciones sobre cómo lo hará el sistema.

Un ejemplo de un requisito funcional sería:

  • Un sistema debe enviar un correo electrónico cada vez que se cumpla una determinada condición (por ejemplo, se realiza un pedido, un cliente se registra, etc.).

Un requisito no funcional relacionado para el sistema puede ser:

  • Los correos electrónicos deben enviarse con una latencia de no más de 12 horas desde dicha actividad.

El requisito funcional es describir el comportamiento del sistema en relación con la funcionalidad del sistema. El requisito no funcional elabora una característica de rendimiento del sistema.

Por lo general, los requisitos no funcionales se dividen en áreas tales como:

  • Accesibilidad
  • Capacidad actual y pronosticada
  • Conformidad
  • Documentación
  • Recuperación de desastres
  • Eficiencia
  • Eficacia
  • Extensibilidad
  • Tolerancia a fallos
  • Interoperabilidad
  • Mantenibilidad
  • Intimidad
  • Portabilidad
  • Calidad
  • Fiabilidad
  • Resiliencia
  • Tiempo de respuesta
  • Robustez
  • Escalabilidad
  • Seguridad
  • Estabilidad
  • Soportabilidad
  • Testabilidad

Una lista más completa está disponible en la entrada de Wikipedia para requisitos no funcionales .

Los requisitos no funcionales a veces se definen en términos de métricas (es decir, algo que se puede medir sobre el sistema) para hacerlos más tangibles. Los requisitos no funcionales también pueden describir aspectos del sistema que no se relacionan con su ejecución, sino con su evolución a lo largo del tiempo (por ejemplo, mantenibilidad, extensibilidad, documentación, etc.).

Requerimientos de proyecto

  • Tienen que ver más con el rol de gestor de proyectos, se usan para dar prioridad a los requerimientos del producto.
  • Estos dos mundos de requerimientos hablan de las prioridades del equipo de trabajo del proyecto.
  • Tiene que ver con requerimientos logísticos, que no tienen que ver con el desarrollo del software.

Riesgos

Los riesgos son importantes para priorizarlos y atacarlos en orden y asegurar que las soluciones arquitectónicas que propongamos resuelvan los problemas más importantes.

Usar escenarios de fracaso que sean medibles y accionables.

“En situaciones de carga pico, los clientes experimentan latencias mayores a cinco segundos.”

“Un atacante podría obtener información confidencial a través de un Ataque de intermediario (Man in the Middle).”

¿Cómo identificamos riesgos?
Requerimientos (Dificultad / Complejidad)
Es importante conocer si el requerimiento es complejo, es decir si la dificultad de resolver este requerimiento es muy alta.
Atributos de calidad (Incertidumbre)
Es importante entender si sabemos o no sabemos cómo mejorar un atributo específico. Cuanta más incertidumbre hay en algo que detectamos que es importante, más alto es el riesgo de esa situación.
Conocimiento del dominio (Riesgo prototípico)
Es importante saber si lo que hemos implementado ya ha sido implementado o no, porque los dominios conocidos suelen tener riesgos prototípicos.

Priorizar riesgos
Es importante porque generalmente no podemos resolver todos, entonces si nos concentramos en resolver riesgos que no eran importantes, entonces estaremos invirtiendo mucho tiempo en algo que no era tan relevante. Debemos siempre tener en cuenta qué riesgos ponen en peligro el éxito o fracaso de la solución. Priorizamos nuestros riesgos y entendemos tanto nosotros como nuestros stakeholders que algunos riesgos no vamos a poder cubrirlos en el primer momento, sino que vamos a postergar el ataque o la mitigación de dichos riesgos para cuándo podamos invertir tiempo en ellos. Así los riesgos y los requerimientos van a ser priorizados y van a poder ser parte de nuestro plan organizado en dónde entendemos qué es lo más importante arquitectónicamente para resolver.

Restricciones

Las restricciones en el contexto de un proceso de desarrollo de software se refiere a las restricciones que limitan las opciones de diseño o implementaciones disponibles al desarrollar.

Los StakeHolders, nos pueden poner limitaciones relacionadas con su contexto de negocio, ejemplo:

• Las limitaciones legales, la implementación de un producto podría tener restricciones en algún país, y esto seria una limitante a considerar para el desarrollo del producto.
• Limitaciones técnicas, relacionadas con integraciones con otros sistemas.
• El ciclo de vida del producto, agregará limitaciones al producto, por ejemplo a medida que avanza el proceso de implementación el modelo de datos va a ser más difícil de modificar.

Nota:
El arquitecto debe balancear entre los requerimiento y las restricciones.

Estilos de Arquitectura

Hay muchas librerías, muchos frameworks, mucho conocimiento arquitectónico implícito entre las comunidades.

¿Qué es un estilo de arquitectura?
Cuando hablamos de estilo de arquitectura hablamos de algo genérico.

Un estilo de arquitectura es una colección de decisiones de diseño, aplicables a un contexto determinado, que restringen las decisiones arquitectónicas específicas en ese contexto y obtienen beneficios en cada sistema resultante.
_Software Architecture: Foundations, Theory and Practice (Taylor, 2010)

Estilos Llamado y Retorno

  • Programa principal y subrutinas: Es el estilo más básico donde se tiene una rutina y se manda a llamar otra subrutina en donde la subrutina puede retornar o no un resultado, pero la rutina principal continua hasta que acabe la subrutina.
  • Orientada a Objetos: Una versión con esteroides del estilo anterior. Se utiliza para aplicaciones que vamos a mantener por mucho tiempo. Tratamos de juntar el estado de la aplicación creando objetos los cuales tienen una interfaz publica (interfaz en este caso se refiere a una definición de funciones o estructura que esta clase puede implementar) donde la llamada no es solo una subrutina, sino objetos que interactuán entre si.
  • Arquitectura multinivel: Son diferentes componentes que se van a comunicar en un orden en especifico donde un componente principal crea el llamado a un componente inferior en algún momento, un ejemplo de esto son las aplicaciones cliente-servidor.

Estilos: Flujo de datos

Este estilo se utiliza cuando tenemos un proceso que tiene que tener una salida clara; pero esa misma salida puede segmentarse en partes. Partes que ya se sabe que hay que hacer.

Lote Secuencial:

  • Se trata de la ejecución de una pieza de código, Ya procesa y asegura de que esta pase a otra etapa o proceso.

Tubos y Filtros:

  • Es un String o un flujo de datos continuo, en donde cada aplicación recibe esos datos. los procesa. y los envía como salida a otra aplicación o quizás. ya hasta al final de la ejecución.

Estilos: Centradas en datos

En el estilo de arquitectura centrados en datos se puede observar es que la aplicación tiene múltiples componentes, pero alguno de ellos se va a concentrar en almacenar los datos, ponerlos disponibles y que hacer para que los datos sean correctos.

Pizarrón: Son diferentes componentes que interactúan con un componente central y cada componente tiene la responsabilidad de procesar, calcular o recibir un dato y escribirlo al componente central. Cuando el componente central ya sabe que tiene todos los datos necesarios puede tener una salida.

Centrado en datos: Consiste en compartir información de una base datos y que varios componentes puedan acceder a la misma, es decir, distintos componentes comparten una misma base de datos.

Experto: En este caso el sistema que centraliza los datos, tiene la capacidad de entender los datos y consultas que realiza el cliente, generando salidas inteligentes. (inteligencia artificial).

Nota: En los estilos de arquitecturas basados en datos siempre vamos a tener esta concentración de cómo hacer para consultar o guardar algo, en cada uno de los estilos vistos se puede ver como el dato tiene diferentes formas o diferentes importancias, en algunos casos se centraliza la información, en otros se tienen procesos claros donde se sabe cuántos datos faltan y cuantos datos se necesitan mientras que en otros casos también los datos puede que no sean conocidos.

Estilos: Componentes independientes

Este tipo de estilo de arquitectura es para desarrollar aplicaciones independientemente y no tener acoplamiento fuerte entre cada uno de nuestros componentes.

  • Invocación implicita: Suele ser basada en eventos, habla de como hacerle para que nuestras aplicaciones se manden mensajes entre si. Cuando se tiene eventos, naturalmente se tienen componentes y un bus de eventos donde los componentes van a publicar eventos y luego el bus de eventos los va a notificar. Aquí se encuentra Publicar y Suscribir que trata de un componente que publica y otro componente que suscribe, todo a través del bus de eventos. También existe el Enterprise Service Bus el cual tiene componentes registrados los cuales se pueden comunicar con el bus, los componentes no se conocen entre si, pero están programados para cumplir con su objetivo.
  • Invocación explicita: Citando a un compañero de este curso: “Tiene que ver con el desarrollo de componentes que sí se conocen entre si, pero se han desarrollado independientemente”. Aquí se encuentra Orientado al Servicio en donde todos los componentes se registran al “Registro central” y después indican donde comunicarse.

Comparando estilos: ¿Cómo elijo?

Estilos Monolíticos:

  • Es más fácil darle prioridad a la eficiencia de las comunicaciones.
  • Son más fáciles de probar.
  • Curva de aprendizaje son más fáciles, todas las piezas estan en el mismo lugar. (Los microservicios son fáciles de entender).
  • La capacidad de modificación es más fácil.
  • La modularización es más fácil de romper, por lo que es más fácil no garantizar esa separación a largo plazo.
  • En la usabilidad, es mas costoso, porque habría que respaldar toda la aplicación y no pequeños microservicios.
  • Puede ser un desafío para el despliegue, porque habría que garantizar que toda la aplicación o sistema se adapta a ese contexto específico.

Estilos Distribuidos:

  • Es más fácil darle prioridad a la eficiencia de las comunicaciones.
  • Para hacer una prueba de principio a fin hay que tener todos los componentes disponibles .
  • La curva de aprendizaje es más difícil, porque habría que entender todas las piezas de los componentes.
  • Al ser desplegadas independientemente, son versionadas independientemente, y esta variación de serviones hace mas complejo su modificación.
  • La modularidad, es más fácil porque los componentes que son desplegados independiente.
  • la disponibilidad se pueden tener multiples copias del sistema. por lo que este disponible es mas barato.
  • La adaptabilidad es más fácil en el despliegue porque los componente se despliegan independientemente en múltiples contextos.

Tener en cuenta los requisitos, los objetivos de negocio / arquitectura de software, atributos de calida/ Estrategias de arquitectura, Escenarios/ Desiciones arquitectonicas. Con el fin de analizar que sacrificios, riesgos y como impacta en mi proyecto

Fuente: Platzi

--

--