Desde hace muchos años, el mundo del desarrollo del software cuenta con lenguajes de modelado de sistemas, tipo UML, ArchiMate o SysML, usados para definir la arquitectura mediante diagramas que ayuden a la comprensión del mismo. Sin embargo en la práctica (al menos la que yo he vivido) poca gente conoce y mucha menos usa algunos de estos lenguajes. Probablemente son tan completos que al final resultan demasiado complejos y con demasiados detalles por lo que se termina optando por diagramas con solo cajas y líneas sin mucho sentido e incongruentes entre sí.
El modelo C4 pretende simplificar la forma de explicar la arquitectura software mediante una "aproximación" al detalle dividida en 4 pasos, o zooms:
Contexto
Contenedores (nada que ver con Docker)
Componentes
Código
Podemos ver el primer nivel, Contexto, como el diagrama que representa al más alto nivel la solución que tratamos de explicar. A su vez, el siguiente nivel de Contenedores (repetimos, nada que ver con contenedores Docker) muestra bloques software de alto nivel mientras que el de Componentes explica contenedor a contenedor qué partes componen cada uno. Por último quien busca el detalle más exhaustivo acude al diagrama de Código donde podemos representar las clases, interfaces, etc y sus relaciones internas.
C4 busca la simplicidad así que trabaja simplemente con:
Person, el típico actor, role, persona, etc en definitiva un humano usando el software
Contenedor, entendido como una aplicación o una base de datos. Algo que tiene que se tiene que ejecutar, por ejemplo: un war corriendo en un Tomcat o un Node, una aplicación que se ejecuta en el desktop del cliente, una base de datos o un simple script.
Componente, en este contexto se entiende como un grupo de funcionalidades relacionadas con un interface común. Lo normal es que un conjunto de componentes que comparten un contenedor se ejecutan en el mismo espacio de trabajo
En este post vamos a ver cómo podemos aplicar este modelo en nuestra documentación usando PlantUML (y/o Asciidoctor).
PlantUML es una herramienta para generar diagramas de software (y otros) partiendo de texto. La idea es muy potente porque te permite tener tus diagramas versionados como si fueran parte del código pudiendo versionarlos en un repositorio, fomentar la revisión, etc. Unido a herramientas como Asciidoctor, donde tu documentación sigue el mismo principio de ser texto y que la herramienta genere el resultado visual, disponemos de una forma cómoda y potente de tener nuestra documentación al día y visualmente atractiva.
PlantUML (https://www.plantuml.com) te permite generar diagramas:
de clases
de actividad
secuencia
componentes
etc
Así mismo cuenta con un sistema para poder extender sus capacidades pudiendo incluir iconos, otros tipos de diagramas, etc que es lo que vamos a usar en este post para demostrar cómo documentar una arquitectura software con C4.
Básicamente la idea es que puedas adjuntar junto a tus explicaciones en Asciidoctor, bloques de texto como los que se muestran a continuación, de tal forma que no necesites herramientas externas ni incluir imágenes que no puedas volver a editar cuando quieras añadir o quitar información.
El primer diagrama que generaremos es un diagrama de Contexto donde mostraremos la foto general sin mucho detalle. Mostraremos las Persons principales así como sistemas externos. En este diagrama no buscamos mostrar tecnología, sino relaciones entre las personas y los sistemas
[plantuml]
----
!include <c4/C4_Context.puml>
!include <office/Users/user.puml>
!include <office/Users/mobile_user.puml>
title Te lo traigo de mi Pueblo
LAYOUT_TOP_DOWN
LAYOUT_WITH_LEGEND()
Person(customer, "<$user>\nCliente", "Un cliente de TelotraigodemiPueblo.")
Enterprise_Boundary(c0, "Te lo traigo de mi Pueblo") {
Person(csa, "<$mobile_user>\nCustomer Service Agent", "Help Desk.")
System(ecommerce, "E-commerce System", "Registro, planificacion y suscripcion.")
}
System_Ext(banco, "PasarelaPago", "Pagos de pedidos.")
Rel_D(customer, csa, "Soporte", "Telefono")
Rel_D(customer, ecommerce, "Crea viajes y realiza pedidos")
Rel_D(ecommerce, banco, "Procesa pago")
----
En el diagrama de contexto simplemente reflejamos Personas (Cliente y Help Desk) e indicamos qué partes
pertenecen al dominio a representar y cuales son externas ( System
vs System_Ext
)
La extensión nos permite de forma muy simple indicar cómo queremos ubicar los elementos entre sí:
Rel(a,b)
una relación entre a y b normal, Rel_D(a,b)
una relación top-down mientras que Rel_U(a,b)
hace que
la relación sea down-top. Podemos usar Rel_L
y Rel_R
para izquierda y derecha
Como hemos dicho, un container es un backend, una página web, una aplicación mobile, en resumen una unidad "ejecutable"
En nuestro ejemplo vamos a disponer de 3 containers: un Single Page Application como front que a través de llamadas http comunicará con otro container Backend, el cual usa una base de datos para guardar la información. ( En nuestro ejemplo por simplicidad, el backend se comunicará con la pasarela de pago directamente aunque podríamos crear otros containers especializados)
[plantuml]
----
!include <c4/C4_Container.puml>
!include <office/Users/user.puml>
!include <office/Users/mobile_user.puml>
!include https://raw.githubusercontent.com/jagedn/mn-plantuml-sprites/master/sprites/grails.puml
title Te lo traigo de mi Pueblo
LAYOUT_TOP_DOWN
LAYOUT_WITH_LEGEND()
Person_Ext(anonymous_user, "Anonymous User")
Person(aggregated_user, "Aggregated User")
Person(administration_user, "Administration User")
System_Boundary(c1, "telotraigodemipueblo"){
Container(web_app, "Web Application", "Vue.js", "Permite ver amigos, viajes, realizar pedidos, etc")
Container(api, "Api", "<$grails>", "Permite ver amigos, viajes, realizar pedidos, etc")
ContainerDb(rel_db, "Relational Database", "MySQL 5.5.x", "Guarda viajes, pedidos, pagos, etc.")
Container(filesystem, "File System", "FAT32", "Imágenes de productos organizadas por carpetas")
}
System_Ext(pasarela, "Pasarela Pagos")
Rel(anonymous_user, web_app, "Uses", "HTTPS")
Rel(aggregated_user, web_app, "Uses", "HTTPS")
Rel(administration_user, web_app, "Uses", "HTTPS")
Rel_D(web_app, api, "Uses", "HTTPS")
Rel(api, rel_db, "Reads from and writes to", "SQL/JDBC, post 3306")
Rel(web_app, filesystem, "Reads from")
Rel_D(api, pasarela, "JSON/Https", "SSL point to point")
Lay_R(rel_db, filesystem)
----
Como podemos ver en este nivel especificamos tecnología (MySQL, Vue, Grails), así como tratamos por igual
diferentes tipos de Containers, tanto aplicaciones como base de datos o ficheros. Mediante ContainerDb
la
librería nos permite personalizar mejor el container para especificar su naturaleza. Así mismo podemos ver
que PlantUML nos permite añadir elementos visuales que mejoren la comprensión del sistema como por ejemplo
el icono de Grails
(usando una librería propia publicada en Github con iconos para Grails, Micronaut y Groovy)
El tercer nivel de zoom dentro del modelo C4 detalla cada Componente o varios en el mismo diagrama si así se desea, plasmando las diferentes partes de aquel.
Por ejemplo en nuestro caso vamos a representar el Container Api
mostrando sus diferentes partes y cómo
se relacionan entre sí.
[plantuml]
----
!include <c4/C4_Component.puml>
title Api Backend de TelotraigodemiPueblo
Container(spa, "Single Page Application", "Vue.js", "Realiza peticiones en nombre del usuario.")
Container_Boundary(api, "API Application") {
Component(sign, "Sign In Controller", "MVC Rest Controlle", "Allows users to sign in to the internet banking system")
Component(accounts, "Accounts Summary Controller", "MVC Rest Controlle", "Provides customers with a summory of their bank accounts")
Component(orders, "Orders Controller", "MVC Rest Controlle", "Provides customers with a summory of their orders")
Component(security, "Security Component", "Spring Bean", "Provides functionality related to singing in, changing passwords, etc.")
Component(accounts_srv, "Accounts Service", "Spring Bean", "Provides functionality related to accounts.")
Component(gwfacade, "Banking System Facade", "Spring Bean", "A facade onto the mainframe banking system.")
}
ContainerDb(rel_db, "Relational Database", "MySQL 5.5.x", "Guarda viajes, pedidos, pagos, etc.")
System_Ext(pasarela, "Pasarela Pagos", "Realiza el cobro de pedidos.")
Rel(spa, sign, "Uses", "JSON/HTTPS")
Rel(spa, accounts, "Uses", "JSON/HTTPS")
Rel(spa, orders, "Uses", "JSON/HTTPS")
Rel(sign, security, "Uses")
Rel(security, rel_db, "Read & write to", "JDBC")
Rel(accounts, accounts_srv, "Uses")
Rel(accounts_srv, rel_db, "Read & write to", "JDBC")
Rel(orders, gwfacade, "Uses")
Rel(gwfacade, pasarela, "Uses", "XML/HTTPS")
----
El último nivel de detalle propuesto por C4 correspondería al de código en el cual el detalle baja hasta especificar las clases, interfaces, relaciones entre ellos etc, en un típico diagrama UML
[plantuml]
----
title Login Service
package "com.puravida.telotraigo.security" #DDDDDD {
class SpringUserService
class UserDetails
class UserNotFoundException
SpringUserService -- UserDetails : create
SpringUserService - UserNotFoundException : throws
}
UserService ()-- SpringUserService
----
La idea fundamental que subyace sobre todo esto es por un lado el demostrar mediante un ejemplo sencillo las posibilidades de realizar diagramas de arquitectura mediante texto versionable y por otra acercarnos a un modelo simple pero potente como es el modelo C4 donde prima la sencillez y una aproximación top-bottom
2019 - 2024 | Mixed with Bootstrap | Baked with JBake v2.6.7 | Terminos Terminos y Privacidad