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 delmismo. Sin embargo en la práctica (al menos la que yo he vivido) poca gente conoce y mucha menos usa algunos de estoslenguajes. Probablemente son tan completos que al final resultan demasiado complejos y con demasiados detallespor lo que se termina optando por diagramas con sólo cajas y líneas sin mucho sentido e incongruentes entre sí.
C4
El modelo C4 pretende simplificar la forma de explicar la arquitectura software mediante una "aproximación" al detalledividida 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 deexplicar. A su vez, el siguiente nivel de Contenedores (repetimos, nada que ver con contenedores Docker) muestra bloquessoftware 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, porejemplo: un war corriendo en un Tomcat o un Node, una aplicación que se ejecuta en el desktop del cliente, unabase 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
PlantUML es una herramienta para generar diagramas de software (y otros) partiendo de texto. La idea es muy potenteporque te permite tener tus diagramas versionados como si fueran parte del código pudiendolos versionar en unrepositorio, fomentar la revisión, etc. Unido a herramientas como Asciidoctor, donde tu documentación sigue el mismoprincipio de ser texto y que la herramienta genere el resultado visual, disponemos de una forma cómoda y potentede 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.
Contexto
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, sinorelaciones entre las personas y los sistemas
!includeurl https://raw.githubusercontent.com/RicardoNiepel/C4-PlantUML/master/C4_Context.puml
!include <office/Users/user.puml>
!include <office/Users/mobile_user.puml>
title Te lo traigo de mi Pueblo
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")
Figure 1. Context
En el diagrama de contexto simplemente reflejamos Personas (Cliente y Help Desk) e indicamos qué partespertenecen 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 quela relación sea down-top. Podemos usar Rel_L
y Rel_R
para izquierda y derecha
Container
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 llamadashttp comunicará con otro container Backend, el cual usa una base de datos para guardar la información. (En nuestro ejemplo por simplicidad, el backendse comunicará con la pasarela de pago directamente aunque podríamos crear otros containers especializados)
!includeurl https://raw.githubusercontent.com/RicardoNiepel/C4-PlantUML/master/C4_Container.puml
!includeurl 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")
Lay_R(rel_db, filesystem)
Como podemos ver en este nivel especificamos tecnología (MySQL, Vue, Grails), así como tratamos por igualdiferentes tipos de Containers, tanto aplicaciones como base de datos o ficheros. Mediante ContainerDb
lalibrería nos permite personalizar mejor el container para especificar su naturaleza. Así mismo podemos verque PlantUML nos permite añadir elementos visuales que mejoren la comprensión del sistema como por ejemploel icono de Grails
(usando una librería propia publicada en Github con iconos para Grails, Micronaut y Groovy)
Component
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ómose relacionan entre sí.
!includeurl https://raw.githubusercontent.com/RicardoNiepel/C4-PlantUML/master/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")
Code
El último nivel de detalle propuesto por C4 correspondería al de código en el cual el detalle baja hasta especificarlas clases, interfaces, relaciones entre ellos etc, en un típico diagrama UML
title Login Service
package "com.puravida.telotraigo.security" #DDDDDD {
class SpringUserService
class UserDetails
class UserNotFoundException
SpringUserService -- UserDetails : create
SpringUserService - UserNotFoundException : throws
}
UserService ()-- SpringUserService
Conclusión
La idea fundamental que subyace sobre todo esto es por un lado el demostrar mediante un ejemplo sencillo las posibilidades derealizar diagramas de arquitectura mediante texto versionable y por otra acercarnos a un modelo simple pero potentecomo es el modelo C4 donde prima la sencillez y una aproximación top-bottom
Top comments (1)
Great write-up, we also published an article on C4 recently - packagemain.tech/p/software-archit...