PlantUML y C4
Tags: asciidoctor, plantuml, model, c4
Published: 2020-07-18 21:06:03

---
title: PlantUML y C4
published: true
date: 2020-07-18 00:00:00 UTC
tags: asciidoctor,plantuml,model,c4
canonical_url: https://jorge.aguilera.soy/blog/2020/plantuml-c4.html
---

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 overview](https://c4model.com/img/c4-overview.png)

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](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")
```

 ![diag 351b0a7054d5305e50798bd657ddb19b](https://jorge.aguilera.soy/images/diag-351b0a7054d5305e50798bd657ddb19b.png)

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)
```

 ![diag fa21c927ef5b1c65cb9b01b2b100d952](https://jorge.aguilera.soy/images/diag-fa21c927ef5b1c65cb9b01b2b100d952.png)

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")
```

 ![diag 674a04f6e0caa86600a0ed9da69f71d5](https://jorge.aguilera.soy/images/diag-674a04f6e0caa86600a0ed9da69f71d5.png)

## 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
```

 ![diag 0fdd2fb08c5df04442986570afd2de63](https://jorge.aguilera.soy/images/diag-0fdd2fb08c5df04442986570afd2de63.png)

## 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