PlantUML es rey

Read in English

Si has conversado conmigo por más de diez minutos, probablemente me has escuchado mencionar PlantUML una o dos veces :). Y es que PlantUML es una de las herramientas más versátiles que he encontrado en mi vida. No importa si estoy programando en C++, NodeJS, Flutter, Helm, Terraform o aún creando un API with swagger, PlantUML está en algún lugar por allí ayudándome a documentar. Una de las ventajas más grandes de PlantUML es su capacidad de crear diagramas con instrucciones textuales, y por consiguiente versionable. Es decir, no tengo que cambiarme el sombrero de programador y ponerme el de artista para crear los gráficos y diagramas que acompañarán mi código, sino que estos son creados al mismo tiempo, y se mantienen frescos a través de todas las evoluciones del código.

Código en PlantUMLResultado
@startuml
rectangle "Reusable designs\n=====\nArchitects create the blueprint once" {
actor "ISO" as iso2
actor Network as network2
actor DevOps as devops2
actor Storage as storage2
[Blueprint] as bp2
[Solution1] as s1
[Solution2] as s2
}
iso2 -> bp2
network2 --> bp2
devops2 --> bp2
bp2 <- storage2
bp2 --> s1
bp2 --> s2
@enduml
@startuml
!include <C4/C4_Container>
title Some Network Automation\nApplication Architecture\nC4 Container
System_Boundary(ssys,Some Network Automation){
Container(sys,Some Network Automation,NodeJS,In-house developed Network Automation)
Container(bull,Bull Queue,Redis/NodeJS,Queuing engine)
ContainerDb(redis,Redis,Caching DB)
}
System_Ext(nac,Network Product,Network Access Control)
System_Ext(mdm,MDM,Device management system)
System_Ext(dns,DNS,DNS & DHCP management system)
System_Ext(cmdb,CMDB,"CMDB, Change Management")
BiRel_R(sys,nac,Reads network devices and writes new role,HTTPS)
Rel(mdm,sys,Reads IPTV devices,HTTPS)
Rel(sys,dns,Writes DHCP reservation,HTTPS)
BiRel(bull,sys,Reads events and writes status,Queue)
BiRel(sys,redis,Reads and Writes lists,Redis,port 6379)
BiRel(bull,redis,Reads and Writes queues,Redis,port 6379)
Rel(sys,cmdb,Writes informational events)
SHOW_LEGEND()
@enduml

Inclusive, lo uso para ilustrar mis cursos de teología en la Universidad, o los sermones en la iglesia.

@startuml
skinparam backgroundColor transparent
(Herodes el Grande) as grande
together {
(Herodes Antipas) as antipas #pink
("Herodes II - Felipe") as felipe
(Aristóbulo) as aristobulo
}
(Herodías) as herodias
(Herodes Agripa) as agripa
grande --> antipas
grande --> aristobulo
grande --> felipe
aristobulo --> herodias
aristobulo --> agripa
felipe <.. herodias #line:green;line.dotted
antipas <.. herodias #line:red;line.dashed;text:red
@enduml

Además, casi todos los sistemas de markdown tienen soporte de plantuml empotrado, o está disponible con un plugin. Por ejemplo,

markdownresultado en HTML
# Diagrama de secuencia

## Ejemplo
```plantuml
@startuml
actor user
control proxy
entity programa
database database
user -> proxy++ : login
proxy -> programa++ : login
programa -> database++ : existe el usuario
database --> programa-- : si
programa -> database++ : consigue actividad del usuario
database --> programa--
programa --> proxy-- : muestra la actividad
proxy --> user--
@enduml
```
## Ventajas
- Primera
- Segunda

Diagrama de secuencia

Ejemplo



Ventajas


  • Primera
  • Segunda

Aunque hay mucho valor en usar PlantUML como herramienta de documentación durante el desarrollo de una aplicación, se convierte en invalorable cuando la usamos para generar diagramas dinámicos en base a la fuente única de la verdad. Cuando queremos saber la arquitectura de nuestra aplicación, no es importante saber cómo la diseñó el desarrollador, sino cómo está en la realidad. Por diferentes motivos la arquitectura actual de nuestra aplicación puede ser diferente de su intención original, por ejemplo, el desarrollador hizo un cambio y olvidó actualizar el documento, o en una emergencia, alguien hizo un cambio directamente en producción. Es importante, por lo tanto, tener la habilidad de ver la situación actual de la aplicación. El siguiente diagrama es un ejemplo de como se puede generar un gráfico dinámicamente en base a información real.

Por razones obvias, generé este diagrama del manifiesto de helm en lugar de la información real de producción, pero el principio es el mismo, el diagrama es generado dinámicamente en base a la información provista por helm.

Otro ejemplo, tengo un utilitario que automáticamente genera un gráfico del esquema de mi base de datos cada vez que hago un cambio en el código, de manera que el gráfico está siempre actualizado:

Captura de pantalla siendo que el gráfico real toma varias páginas debido a la complejidad del esquema de la base de datos

No es perfecto

Dibujos artísticos

Sin embargo, hay algunas otras áreas de la vida para las que yo quisiera tener una herramienta como PlantUML, para las cuáles PlantUML no siempre es la más adecuada. Por ejemplo, hace tiempo dejé de usar PowerPoint por la insistencia de Microsoft, y todos sus competidores, en usar formatos cerrados e incompatibles con sistemas de versión moderno[1]. En su lugar uso marp que me permite usar markdown, y no solamente produce las presentaciones más limpias y consistentes que he creado, sino que además, todo el contenido de todas las presentaciones que he hecho durante años cabe en un diminuto repositorio de git. Aunque es posible usar PlantUML para ilustrar algunos de mis slides, en algunas oportunidades, me gustaría poder crear ilustraciones como las de SmartArt(TM), pero con la simpleza de PlantUML.

Por ejemplo, me tomó más o menos 30 segundos hacer este gráfico en PowerPoint. Puse “Insertar SmartArt”, escogí la pirámide, eliminé uno de los niveles, escribí las dos palabras, y cambié el tamaño del triángulo superior para ser mucho más pequeño que el otro y voilá:

Alguien (tal vez yo cuando tenga un tiempo libre), podría diseñar un sistema parecido a PlantUML (o aumentarlo) para que se pueda hacer algo parecido y mantener una lista de arte prefabricado que pueda ser fácilmente adaptado por el usuario:

@startart
type=piramide
style=flat
elements=[
  {size:10%,color:yellow,label:Inspiration}
  {size:90%,color:blue,label:Perspiration}
]
@endart

Usuarios

Crear gráficos en PlantUML es muy simple, y por más que todos sus fanáticos insisten que es muchísimo más fácil de usar que tener que dibujar con el mouse, o jalar flechas en la pantalla, hay personas que nunca lo adoptarán. Parece que para estar en el grupo de los que les encanta crear gráficos en base a instrucciones en texto es necesario tener una mentalidad de desarrollador. Aunque es muy fácil para cualquier persona que escriba código, aún para los desarrolladores novatos, para otros es una práctica extraña y ajena.

Audiencia

Con respecto a los consumidores, los gráficos de PlantUML no son “pixel perfect”, en otras palabras, no esperes gráficos que podrás usar para hacer una presentación a tu CEO. El énfasis de PlantUML es la capacidad de crear gráficos automáticamente, basados en instrucciones de texto, y por lo tanto, la máquina creadora decide dónde colocar los diferentes objetos en la pantalla. Estas decisiones no siempre corresponden a nuestros gustos y quisieramos mover uno de los objetos unos milimetros a la izquierda, o ponerlo encima de otro, lastimosamente, eso no es posible, lo que decide PlantUML es lo que recibes, punto.

Postproceso

La facilidad de crear gráficos en base a texto tiene muchísimas aplicaciones, pero como dijimos antes, los resultados no son necesariamente suficientemente pulcros como para poner en una presentación para los altos ejecutivos. Pero los gráficos de PlantUML tienen la opción de ser generados en PNG o en SVG. Sabemos que el PNG es un formato que describe el gráfico en pixeles, pero no así el SVG que usa un formato de vectores, es decir, describe las lineas, rectángulos, círculos, textos que hay en el gráfico para poder reproducirlos en cualquier dimensión. Me encantaría que alguien (tal vez yo en mi tiempo libre) creara una herramienta de postproceso que pudiera tomar un SVG generado por PlantUML y permitiera manipular los objetos para conseguir el resultado “pixel perfect” que se pueda usar en presentaciones.

Soluciones creativas

Cuando PlantUML provee una solución menos que satisfactoria, uno siempre puede escribir su propia solución extendiendo PlantUML. Por ejemplo, PlantUML tienen algo llamado wbs para describir jerarquías como un orgchart, pero es demasiado rígido y limitado. Por ejemplo,

@startwbs
* **My company**\nBill Rogers, CEO
** **Ofice of the CTO**\n[backfill], CTO
*** **Consultant**\nDonna Masick
*** **Engineering**\nFelishia Laquish, Director
**** **Design**\nKarla Mamani, Manager
***** Jason Miller
***** Thomas Albretch
***** Liam Cortez
***** Boris Cybrinsky
***** Carlos Rodriguez
**** **Build**\nCirilo Mann, Manager
***** Sam Adams
***** Victor Nakazaki
***** William Trent
***** John Harding
***** Clyde Albertson
***** Violeta Dominique
**** **Run**\nJim Madison, Manager
*****< Chris Branson
*****< Naomi Schultz
*****< Brandon Alonso
*****> Albert Romero
*****> Sandra Smith
*** **Consultant**\nHorace Smith
@endwbs

Como pueden ver no tengo mucho control sobre la dirección y el aspecto de las ramas (solo el segundo nivel se alínea horizontalmente), aunque sí es posible cambiar colores, pero en general no es suficientemente flexible para usar en casos reales.

Las buenas noticias son que si ninguno de los tipos de diagramas de PlantUML te convencen, siempre puedes usar GraphViz, la base sobre la cual está construída PlantUML. Por ejemplo, con un poquito de trabajo construí una librería que luego puedo utilizar para crear un orgchart que se ve mucho mejor:

@startuml
!include https://gitlab.migrandama.com/foss/plantuml-templates/-/raw/main/org-chart.puml
!$managerColor="#503000"
digraph "org-chart" {
rankdir="TB" splines="true" overlap="false" nodesep="0.2" ranksep="0.001" fontname="Arial" fontsize="9" style="rounded,filled" fillcolor="#ffffff" compound="true"
edge [penwidth="3.0" color="#00000033" fontname="Arial" fontsize="9" dir=none ]
node [color="#f09030" fontcolor="#503000"]

manager(billr,Bil Rogers,My company,CEO)
manager(backfill,"[backfill]",Office of the CTO,CTO,billr,'fillcolor=lightgray color=lightgray fontcolor="#909090"')
individual(donna,Donna Masick,Consultant,backfill)
manager(felishia,Felishia Laquish,Engineering,Director,backfill)
individual(horace,Horace Smith,Consultant,backfill)
manager(karla,Karla Mamani,Design,Manager,felishia)
manager(cirilo,Cirilo Mann,Build,Manager,felishia)
manager(jim,Jim Madison,Run,Manager,felishia)
!$designers = {"members":["Jason Miller","Thomas Albretch","Liam Cortez","Boris Cybrinsky","Carlos Rodriguez"]}
team(designers,Designers,$designers.members,karla)
!$builders = {"members":["Sam Adams","William Trent","John Harding","Clyde Albertson","Violeta Dominique"]}
team(builders,Builders,$builders.members,cirilo)
!$dc = {"members":["Chris Branson","Naomi Schultz","Brandon Alonso"]}
team(dc,Data Center,$dc.members,jim)
!$cloud = {"members":["Albert Romero","Sandra Smith"]}
team(cloud,Cloud,$cloud.members,jim);
}
@enduml

Una de las funciones menos conocidas de PlantUML es su preprocesador. El gráfico anterior está construido en base al preprocesador. Usando una función extra del preprocesador, %load_json, y publicando la información para el orgchart en algún lugar con formato JSON, entonces el gráfico anterior podría generarse dinámicamente:

!include https://gitlab.migrandama.com/foss/plantuml-templates/-/raw/main/org-chart.puml
!$org_data = %load_json("https://migrandama.com/management/org_data")
!$managerColor="#503000"
digraph "org-chart" {
  rankdir="TB" splines="true" overlap="false" nodesep="0.2" ranksep="0.001" fontname="Arial" fontsize="9" style="rounded,filled" fillcolor="#ffffff" compound="true"
  edge [penwidth="3.0" color="#00000033" fontname="Arial" fontsize="9" dir=none ]
  node [color="#f09030" fontcolor="#503000"]
  officeEntity($org_data)
}

Asumiendo que los datos servidos por el URL contienen la misma información que usamos para crear el orgchart anterior, esto sería todo el código de PlantUML necesario para generar el mismo gráfico, de allí en adelante, solo se necesitaría mantener la información actualizada en el archivo json y el orgchart siempre estará fresco.

Concluyendo

¿Por qué digo que PlantUML es una de las herramientas más poderosas y versátiles de mi repertorio? pues porque la uso en actividades diversas de mi vida, y casi siempre me ahorra muchísimo tiempo generando un gráfico de texto de lo que me hubiera tomado dibujar, y eso sin considerar todo el tiempo que tomaría mantener al día el dibujo cuando la información cambia.


1 Microsoft insiste en su modelo cerrado de versionamiento que a) Sólo funciona si lo enciendes, pero cualquiera puede apagarlo y b) No guarda una historia segura de quién hizo cuál cambio.