Hlavní navigace

Tvorba sekvenčních diagramů v Pythonu s využitím knihovny Napkin

18. 5. 2021
Doba čtení: 27 minut

Sdílet

 Autor: Pavel Tišnovský
Ve druhé části miniseriálu o tvorbě grafů a diagramů v univerzálním programovacím jazyku (a nikoli v DSL) se zaměříme na knihovnu Napkin určené pro vykreslení sekvenčních diagramů (UML) přímo na základě kódu v Pythonu.

Obsah

1. Tvorba sekvenčních diagramů v Pythonu s využitím knihovny Napkin

2. Nástroj PlantUML

3. Vygenerování sekvenčních diagramů přímo v PlantUML

4. Složitější příklady sekvenčních diagramů

5. Zobrazení doby zpracování dotazu a čekání na odpověď

6. Sekvenční diagramy a knihovna Napkin

7. Instalace knihovny Napkin

8. Sekvenční diagram vygenerovaný knihovnou Napkin

9. Vykreslení diagramu přes lokální instalaci PlantUML

10. Vykreslení diagramu knihovnou Napkin (přes PlantUML na serveru)

11. Nepatrně složitější diagram: three-way handshake

12. Zobrazení doby zpracování popř. čekání na odpověď

13. Reprezentace několika dotazů v sekvenčním diagramu

14. Specifikace opakujících se sekvenčních operací (loop)

15. Vnořené cykly (loop) v diagramu

16. Seskupení zpráv v diagramu

17. Poznámky přiřazené k uzlům, zprávám či skupinám

18. Repositář s demonstračními příklady

19. Odkazy na články s tématem programové tvorby grafů a diagramů

20. Odkazy na Internetu

1. Tvorba sekvenčních diagramů v Pythonu s využitím knihovny Napkin

Na předchozí článek o knihovně Rhizome dnes navážeme. Popíšeme si totiž knihovnu nazvanou Napkin. Tato knihovna je určena pro vykreslení takzvaných sekvenčních diagramů, které jsou definovány v UML (Unified Modeling Language). Důležité přitom je, že pro popis sekvenčních diagramů je použit přímo univerzální programovací jazyk Python a nikoli specializovaný jazyk (DSL – Domain-Specific Language). A jaké jsou výhody použití Pythonu namísto DSL? Především je Python podporován mnoha integrovanými vývojovými prostředími (IDE), programátorskými textovými editory i dalšími nástroji, mezi něž patří například lintery apod. Navíc může být popis sekvenčních diagramů kódem napsaným v Pythonu pro mnoho vývojářů idiomatický a tudíž může být tvorba diagramů rychlejší a vedoucí k menšímu množství chyb.

Obrázek 1: Jednoduchý diagram tříd vytvořený nástrojem PlantUML zmíněným v navazující kapitole.

Vzhledem k tomu, že výstupem z Napkinu je popis sekvenčního diagramu ve formátu akceptovaného nástrojem PlantUML, zaměříme se v úvodních kapitolách na popis alespoň základních možností tohoto nástroje – ovšem nejedná se o nosné téma celého článku.

Obrázek 2: Třída s atributy a metodami, které mají různá přístupová práva. Povšimněte si oddělení atributů od metod. To je ve skutečnosti provedeno automaticky.

2. Nástroj PlantUML

Dále popsaná aplikace Napkin je postavena na nástroji nazvaném PlantUML (http://plantuml.sourceforge.net/). PlantUML dokáže na základě textového popisu UML diagramu vytvořit bitmapový obrázek (PNG) či vektorovou kresbu (SVG) s tímto diagramem, přičemž uživatel může do jisté míry ovlivnit způsob jeho vykreslení, přidat popis hran, seskupit uzly v diagramu, změnit barvy hran i uzlů, přidat do uzlů ikony apod. V současné verzi PlantUML jsou podporovány následující typy UML diagramů:

  • Diagram aktivit
  • Sekvenční diagram
  • Diagram tříd
  • Diagram objektů
  • Diagram komponent
  • Diagram užití
  • Stavový diagram
  • Diagram načasování operací (ve vývoji)
  • Deployment diagram (pravděpodobně nemá ekvivalentní český překlad)
Poznámka: ve fázi přípravy jsou i další typy diagramů, například často využívaný Ganttův diagram, myšlenková mapa atd.

Obrázek 3: Jednoduchý diagram aktivit vygenerovaný nástrojem PlantUML.

Ve skutečnosti sice specifikace UML popisuje i další typy diagramů, ovšem PlantUML s velkou pravděpodobností dokáže pokrýt většinu potřeb analytiků i programátorů, protože v nabídce podporovaných diagramů jsou zastoupeny všechny tři kategorie: popis struktury informačního systému, popis chování informačního systému a popis interakce či komunikace jak v rámci systému, tak i mimo něj.

PlantUML je naprogramovaný v Javě, ovšem podobně jako tomu bylo v případě již popsaného nástroje Ditaa se jedná o relativně malý program, který pro svůj běh nevyžaduje enormní množství zdrojů (diskový prostor, RAM atd.). Pro uživatele PlantUML je na adrese http://sourceforge.net/pro­jects/plantuml/files/plan­tuml.jar/download k dispozici spustitelný Java archiv, dále je vhodné si stáhnout referenční příručku k jazyku z adresy http://plantuml.sourcefor­ge.net/PlantUML_Language_Re­ference_Guide.pdf.

Obrázek 4: Jednoduché rozvětvení reprezentované v diagramu aktivit vytvořeného nástrojem PlantUML.

3. Vygenerování sekvenčních diagramů přímo v PlantUML

Nástroj PlantUML podporuje mnoho typů diagramů (vypsali jsme si je v předchozí kapitole). Mezi ně patří například stavové diagramy, které dokážou názorně popsat stavy systému i možné přechody mezi jednotlivými stavy. Ovšem v mnoha případech vzniká potřeba podrobněji popsat i interakci mezi popisovaným systémem a jeho okolím, interakci mezi dvěma nebo více moduly systému či (na té nejpodrobnější úrovni) interakci probíhající mezi jednotlivými objekty, z nichž se systém skládá. Pro tento účel slouží v jazyku UML především sekvenční diagramy (sequence diagrams), v nichž lze velmi názorným způsobem naznačit časovou posloupnost posílání zpráv mezi různými typy objektů, popř. k zobrazené posloupnosti zpráv přidat další komentáře, ikony a značky. Jeden z typických a poměrně často v praxi používaných příkladů použití sekvenčních diagramů je popis komunikace s využitím síťových i jiných protokolů. Ostatně právě na síťovém protokolu (navázání spojení a zrušení spojení) si sekvenční diagramy ukážeme prakticky v navazujících dvou kapitolách.

Nejjednodušší sekvenční diagram je možné v nástroji PlantUML deklarovat následujícím způsobem. S využitím symbolu -> je naznačeno poslání zprávy mezi dvojicí objektů, v tomto případě mezi klientem a serverem. Sekvenční diagram neobsahuje žádné počáteční ani koncové pseudostavy, což je jeden z rozpoznávacích znaků mezi sekvenčním diagramem a stavovým diagramem. Proto také při odstranění pseudostavů může PlantUML automaticky zaměnit stavový diagram za diagram sekvenční, což je samozřejmě chyba (způsobená tím, že se PlantUML snaží o automatické doplnění kontextových informací):

@startuml
 
Client -> Server: SYN
 
@enduml

Obrázek 5: Sekvenční diagram vytvořený na základě prvního demonstračního příkladu.

Druhý příklad je nepatrně složitější a ukazuje způsob navázání komunikace v protokolu TCP (tzv. three-way handshake), přesněji řečeno ideální stav, kdy se navázání spojení podaří:

@startuml
 
Client -> Server: SYN
Server -> Client: SYN-ACK
Client -> Server: ACK
 
@enduml

Obrázek 6: Sekvenční diagram vytvořený na základě druhého demonstračního příkladu.

Deklarace předchozího diagramu byla pravděpodobně pro mnoho vývojářů poněkud nešikovná, protože se na druhém řádku prohodila jména komunikujících objektů. To lze snadno napravit, protože symbol -> je možné nahradit symbolem <-, který (samozřejmě) značí poslání zprávy opačným směrem, ostatně tímto směrem bude mířit i šipka ve výsledném diagramu:

@startuml
 
Client -> Server: SYN
Client <- Server: SYN-ACK
Client -> Server: ACK
 
@enduml

Obrázek 7: Sekvenční diagram vytvořený na základě třetího demonstračního příkladu.

Podívejme se ještě na nepatrně složitější příklad: ukončení spojení, tentokrát způsobem označovaným four-way handshake (spojení v TCP ukončují a vzájemně si ho potvrzují obě strany). Jednotlivé zprávy byly navíc automaticky očíslovány, což zajistilo uvedení klíčového slova autonumber:

@startuml
 
autonumber
 
Client -> Server: FIN
Client <- Server: ACK
Client <- Server: FIN
Client -> Server: ACK
 
@enduml

Obrázek 8: Sekvenční diagram vytvořený na základě čtvrtého demonstračního příkladu.

4. Složitější příklady sekvenčních diagramů

Sekvenční diagramy mohou být i poměrně rozsáhlé, což je ukázáno na dalším příkladu získaném z reálného projektu (resp. z fáze jeho prvotního návrhu). Povšimněte si možnosti specifikace stylu vykreslení uzlů i tvaru uzlů (actor, database, participant):

@startuml
 
header Sequence diagram for data flow in Content Service
footer Copyright © 2020 Red Hat, Inc. Author: Pavel Tisnovsky
 
actor "Author of\nrule content" as author
database "Internal\nGitLab\nrepository\n<&fork>" as gitlab
database "External\nGitHab\nrepository\n<&fork>" as github
participant "OpenShift\ntooling" as openshift #ffa0a0
participant "Insights\nContent Service" as content_service #a0a0ff
participant "Smart\nProxy" as smart_proxy #a0a0ff
collections "REST API\nconsumers" as consumers
 
== New content or update of existing content ==
author -> gitlab: Merge into\nmain branch
 
== Data synchronization to Content Service ==
gitlab -> github: New commit(s)
github -> github: Merge commit
gitlab -> openshift: Webhook - new changes
openshift -> github:  Clone\nrepository
github -> openshift: Repository content
openshift -> openshift: Rebuild image
note right: OpenShift rebuild Insights\nContent Service image\nwith new rules content included
openshift -> openshift: Restart pod
openshift -> content_service: Set replicas > 0
note right: Now the Content Service\nexposes new rules content\nvia its REST API
 
== Synchronization between Smart Proxy and Content Service ==
smart_proxy -> content_service: Get new content\nfor all rules
note right: Smart proxy needs\nto periodically\nupdate its cache
content_service -> smart_proxy: Here's\nrequired\ncontent
smart_proxy -> smart_proxy: Update content\nin cache
 
== Providing recommendations to consumers ==
consumers -> smart_proxy: Get\nrecommendations\norg ID\ncluster ID
smart_proxy -> smart_proxy: Merge results\nwith content
smart_proxy -> consumers: Recommendations\nfor cluster
 
@enduml

Obrázek 9: Sekvenční diagram vykreslený podle předchozího popisu.

V sekvenčních diagramech je možné použít i ikony (Kafka, Kubernetes atd.):

@startuml
 
!include <cloudinsight/kafka>
!include <kubernetes/k8s-sprites-unlabeled-25pct>
 
header Sequence diagram for the whole CCX (external) data pipeline
footer Copyright © 2020 Red Hat, Inc. Author: Pavel Tisnovsky
 
participant "Smart\nProxy" as smart_proxy #a0a0ff
participant "3Scale" as 3scale
box "Insights operator" #ddffdd
participant "<$master>\nControl logic" as operator
database "IO memory cache" as cache
end box
entity "CRD" as crd
collections "OCP\nWebConsole" as console
 
== Pulling data from Smart Proxy ==
operator -> 3scale: Get\nrecommendations\norg ID\ncluster ID
3scale -> smart_proxy: Get\nrecommendations\norg ID\ncluster ID
smart_proxy -> 3scale: Recommendations\nfor cluster
3scale -> operator: Recommendations\nfor cluster
 
== Exposing recommendations ==
operator -> cache: Store\nrecommendations
cache -> crd: Expose\nrecommendations
 
== Pulling from OCP WebConsole ==
console -> crd: Read\nrecommendations
crd -> console: Here are\nrequired data
 
@enduml

Obrázek 10: Sekvenční diagram vykreslený podle předchozího popisu.

5. Zobrazení doby zpracování dotazu a čekání na odpověď

Často se setkáme s požadavkem, aby se v sekvenčním diagramu zobrazila doba zpracování dotazu (požadavku). Tato doba se v diagramech znázorňuje vertikálním sloupečkem, který spojuje šipky s dotazem a odpovědí. V PlantUML se požadovaného výsledku dosáhne použitím klauzulí activate jméno_uzlu a deactivate jméno_uzlu, což je ukázáno v následujícím příkladu odvozeném od příkladu předchozího:

@startuml
 
!include <cloudinsight/kafka>
!include <kubernetes/k8s-sprites-unlabeled-25pct>
 
header Sequence diagram for the whole CCX (external) data pipeline
footer Copyright © 2020 Red Hat, Inc. Author: Pavel Tisnovsky
 
participant "Smart\nProxy" as smart_proxy #a0a0ff
participant "3Scale" as 3scale
box "Insights operator" #ddffdd
participant "<$master>\nControl logic" as operator
database "IO memory cache" as cache
end box
entity "CRD" as crd
collections "OCP\nWebConsole" as console
 
== Pulling data from Smart Proxy ==
operator -> 3scale: Get\nrecommendations\norg ID\ncluster ID
activate 3scale
3scale -> smart_proxy: Get\nrecommendations\norg ID\ncluster ID
activate smart_proxy
smart_proxy -> 3scale: Recommendations\nfor cluster
deactivate smart_proxy
3scale -> operator: Recommendations\nfor cluster
deactivate 3scale
 
== Exposing recommendations ==
operator -> cache: Store\nrecommendations
cache -> crd: Expose\nrecommendations
 
== Pulling from OCP WebConsole ==
console -> crd: Read\nrecommendations
activate crd
crd -> console: Here are\nrequired data
deactivate crd
 
@enduml

Obrázek 11: Sekvenční diagram vykreslený podle předchozího popisu.

Naprosto stejným způsobem lze v diagramu naznačit dobu čekání na odpověď. V takovém případě se jedná o sloupeček zobrazený na straně dotazujícího uzlu. Povšimněte si, že příkazové dvojice activate/deactivate jsou vnořeny a typicky se nepřekrývají (proto je možné, jak si ukážeme dále, použít blok with):

@startuml
 
!include <cloudinsight/kafka>
!include <kubernetes/k8s-sprites-unlabeled-25pct>
 
header Sequence diagram for the whole CCX (external) data pipeline
footer Copyright © 2020 Red Hat, Inc. Author: Pavel Tisnovsky
 
participant "Smart\nProxy" as smart_proxy #a0a0ff
participant "3Scale" as 3scale
box "Insights operator" #ddffdd
participant "<$master>\nControl logic" as operator
database "IO memory cache" as cache
end box
entity "CRD" as crd
collections "OCP\nWebConsole" as console
 
== Pulling data from Smart Proxy ==
operator -> 3scale: Get\nrecommendations\norg ID\ncluster ID
activate operator
activate 3scale
3scale -> smart_proxy: Get\nrecommendations\norg ID\ncluster ID
activate smart_proxy
smart_proxy -> 3scale: Recommendations\nfor cluster
deactivate smart_proxy
3scale -> operator: Recommendations\nfor cluster
deactivate 3scale
deactivate operator
 
== Exposing recommendations ==
operator -> cache: Store\nrecommendations
cache -> crd: Expose\nrecommendations
 
== Pulling from OCP WebConsole ==
console -> crd: Read\nrecommendations
activate console
activate crd
crd -> console: Here are\nrequired data
deactivate crd
deactivate console
 
@enduml

Obrázek 12: Sekvenční diagram vykreslený podle předchozího popisu.

6. Sekvenční diagramy a knihovna Napkin

Nyní již máme k dispozici všechny informace potřebné pro porozumění sekvenčním diagramům v nástroji PlantUML. Ve druhé části článku se tedy zaměříme na popis knihovny Napkin určené pro programovací jazyk Python. Tato knihovna, která je dostupná jak na GitHubu, tak i na PyPi, umožňuje definici sekvenčních diagramů přímo v Pythonu s využitím bloků with, které reprezentují kontext, v němž je zpráva poslána popř. zpracovávána. Interně se diagramy převádí z Pythonu právě do PlantUML a následně jsou vykresleny – implicitně tak, že se definice diagramu pošle na PlantUML server, který vrátí vykreslený výsledek. V případě potřeby je však pochopitelně možné použít i lokální instalaci PlantUML.

7. Instalace knihovny Napkin

Instalace knihovny Napkin je snadná (alespoň v porovnání s PlantUML), protože je distribuována formou standardně připraveného balíčku pro jazyk Python a je dostupná na PyPi. Instalaci provedeme nástrojem pip popř. pip3 a pochopitelně je podporována i instalace do virtuálního prostředí Pythonu (virtualenv):

$ pip3 install --user napkin

Průběh instalace naznačuje, že Napkin má jen minimální závislosti:

Collecting napkin
  Downloading https://files.pythonhosted.org/packages/f4/71/d00d15190bd5a2e630ead71158aca8d5784abc02452df66f8645cf59d055/napkin-0.6.8-py3-none-any.whl
Requirement already satisfied: requests in /usr/lib/python3.8/site-packages (from napkin)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/lib/python3.8/site-packages (from requests->napkin)
Requirement already satisfied: idna<2.8,>=2.5 in /usr/lib/python3.8/site-packages (from requests->napkin)
Requirement already satisfied: urllib3<1.25,>=1.21.1 in /usr/lib/python3.8/site-packages (from requests->napkin)
Installing collected packages: napkin
Successfully installed napkin-0.6.8

Po instalaci zjistíme, kde je umístěn spustitelný skript představující vstupní bod do Napkinu:

$ whereis napkin
 
napkin: /home/ptisnovs/.local/bin/napkin
Poznámka: je dobré ověřit, zda je vypsaný adresář na PATH.

Nakonec otestujeme, jestli je možné Napkin spustit z příkazové řádky a mimochodem zjistíme i povolené přepínače:

$ napkin --help
 
usage: napkin [-h]
              [--output-format {plantuml,plantuml_png,plantuml_svg,plantuml_txt}]
              [--output-dir OUTPUT_DIR] [--version] [--server-url SERVER_URL]
              srcs [srcs ...]
 
Generate UML sequence diagram from Python code
 
positional arguments:
  srcs                  Python file or directory containing diagram functions
 
optional arguments:
  -h, --help            show this help message and exit
  --output-format {plantuml,plantuml_png,plantuml_svg,plantuml_txt}, -f {plantuml,plantuml_png,plantuml_svg,plantuml_txt}
  --output-dir OUTPUT_DIR, -o OUTPUT_DIR
  --version             show program's version number and exit
  --server-url SERVER_URL
                        (only for plantuml_png/svg format) Default is the
                        public server
 
Supported output formats:
  plantuml         : PlantUML script (default)
  plantuml_png     : PlantUML script and PNG image
  plantuml_svg     : PlantUML script and SVG image
  plantuml_txt     : PlantUML script and ASCII art text

8. Sekvenční diagram vygenerovaný knihovnou Napkin

Podívejme se nyní na způsob definice sekvenčního diagramu s využitím prostředků programovacího jazyka Python. Diagram se dvěma komunikujícími objekty a jednou zprávou může být zapsán následujícím způsobem:

1       import napkin
 
 
2       @napkin.seq_diagram()
3       def client_server_1(c):
4           client = c.object('Client')
5           server = c.object('Server')
 
6           with client:
7               server.SYN()

Jednotlivé části skriptu:

  1. Budeme používat dekorátor z balíčku napkin
  2. Dekorace funkce představující zápis komunikace mezi objekty
  3. Ze jména funkce se odvodí jméno souboru s výsledným diagramem (parametr je doplněn před dekorátor)
  4. První komunikující objekt se specifikací jeho jména tak, jak bude zobrazeno v diagramu
  5. Druhý komunikující objekt se specifikací jeho jména tak, jak bude zobrazeno v diagramu
  6. Začátek komunikace inicializovaného objektem klient
  7. Poslání zprávy objektu server se zapisuje formou volání funkce

Vytvoření deklarace diagramu v jazyku akceptovaném nástrojem PlantUML:

$ napkin client-server-1.py 
 
Load file : client-server-1.py
File generated : ./client_server_1.puml

Výsledný soubor vypadá následovně:

@startuml
participant Client
participant Server
 
Client -> Server : SYN()
@enduml

9. Vykreslení diagramu přes lokální instalaci PlantUML

V případě, že máte k dispozici lokálně nainstalovaný nástroj PlantUML, je možné si nechat vygenerovat diagram v rastrovém formátu PNG následujícím příkazem (pro zajímavost je cesta k JAR archivu s PlantUML nestandardní):

$ java -jar ~/tools/plantuml.jar client_server.puml

Obrázek 13: Výsledek předchozího příkazu.

Alternativně je možné získat výstup ve vektorovém formátu SVG:

$ java -jar ~/tools/plantuml.jar client_server.puml -tsvg

Poslední možností je výstup do textového formátu (ASCII art):

$ java -jar ~/tools/plantuml.jar client_server.puml -ttxt

Výsledek v tomto případě vypadá následovně:

     ┌──────┐          ┌──────┐
     │Client│          │Server│
     └──┬───┘          └──┬───┘
        │      SYN()      │
        │ ────────────────>
     ┌──┴───┐          ┌──┴───┐
     │Client│          │Server│
     └──────┘          └──────┘

10. Vykreslení diagramu knihovnou Napkin (přes PlantUML na serveru)

Implicitně ovšem knihovna Napkin nepoužívá lokální instalaci PlantUML, ale posílá definici sekvenčního diagramu na veřejně dostupný server, jenž vykreslení diagramu provede a pošle zpátky výsledek. Pokud tedy váš diagram neobsahuje žádná citlivá data, je vykreslení diagramu ještě jednodušší (a server je navíc pro většinu případů i dostatečně rychlý).

Vytvoření popisu diagramu v jazyku podporovaného PlantUML:

$ napkin --output-format plantuml client-server-1.py
 
Load file : client-server-1.py
File generated : ./client_server.puml

Vykreslení diagramu do rastrového obrázku PNG:

$ napkin --output-format plantuml_png client-server-1.py
 
Load file : client-server-1.py
File generated : ./client_server.puml, ./client_server.png

Vykreslení diagramu do vektorové kresby SVG:

$ napkin --output-format plantuml_svg client-server-1.py
 
Load file : client-server-1.py
File generated : ./client_server.puml, ./client_server.svg

Výstup do textového souboru (ASCII art):

$ napkin --output-format plantuml_txt client-server-1.py
 
Load file : client-server-1.py
File generated : ./client_server.puml, ./client_server.txt

Výsledek je v tomto případě totožný s lokálním renderingem:

     ┌──────┐          ┌──────┐
     │Client│          │Server│
     └──┬───┘          └──┬───┘
        │      SYN()      │
        │ ────────────────>
     ┌──┴───┐          ┌──┴───┐
     │Client│          │Server│
     └──────┘          └──────┘

11. Nepatrně složitější diagram: three-way handshake

Vyzkoušejme si nyní vytvořit nepatrně složitější diagram s již zmíněným three-way handskakem. První varianta tohoto diagramu může vypadat takto (jednotlivé zprávy jsou zdánlivě nezávislé):

import napkin
 
 
@napkin.seq_diagram()
def client_server_2(c):
    client = c.object('Client')
    server = c.object('Server')
 
    with client:
        server.SYN()
 
    with server:
        client.SYN_ACK()
 
    with client:
        server.ACK()
Poznámka: to, že jednotlivé zprávy nezávisí na sobě (netvoří sekvenci) je ve skutečnosti špatné řešení.

Obrázek 14: Výsledek předchozího příkazu.

Výsledek v textovém formátu:

     ┌──────┐          ┌──────┐
     │Client│          │Server│
     └──┬───┘          └──┬───┘
        │      SYN()      │
        │ ────────────────>
        │                 │
        │    SYN_ACK()    │
        │ <────────────────
        │                 │
        │      ACK()      │
        │ ────────────────>
     ┌──┴───┐          ┌──┴───┐
     │Client│          │Server│
     └──────┘          └──────┘

12. Zobrazení doby zpracování popř. čekání na odpověď

Víme již, že v sekvenčním diagramu lze zobrazit i dobu zpracování požadavku popř. dobu čekání na odpověď. K tomuto účelu slouží vertikální prázdné sloupečky. V nástroji Napkin můžeme tyto sloupečky přidat s využitím konstrukce with v Pythonu:

import napkin
 
 
@napkin.seq_diagram()
def client_server_3(c):
    client = c.object('Client')
    server = c.object('Server')
 
    with client:
        with server.SYN():
            with client.SYN_ACK():
                server.ACK()

Obrázek 15: Výsledek v grafické podobě.

Výsledek v textové podobě:

     ┌──────┐          ┌──────┐
     │Client│          │Server│
     └──┬───┘          └──┬───┘
        │     SYN()      ┌┴┐
        │ ──────────────>│ │
        │                │ │
       ┌┴┐   SYN_ACK()   │ │
       │ │ <─────────────│ │
       └┬┘               └┬┘
        │      ACK()      │
        │ ────────────────>
     ┌──┴───┐          ┌──┴───┐
     │Client│          │Server│
     └──────┘          └──────┘

Odlišný sekvenční diagram, ovšem založený na stejných zprávách (je použitých v jinak navrženém bloku with):

import napkin
 
 
@napkin.seq_diagram()
def client_server_4(c):
    client = c.object('Client')
    server = c.object('Server')
 
    with client:
        with server.SYN():
            client.SYN_ACK()
        server.ACK()

Obrázek 16: Výsledek v grafické podobě.

Výsledek v textové podobě:

     ┌──────┐          ┌──────┐
     │Client│          │Server│
     └──┬───┘          └──┬───┘
        │     SYN()      ┌┴┐
        │ ──────────────>│ │
        │                └┬┘
        │    SYN_ACK()    │
        │ <────────────────
        │                 │
        │      ACK()      │
        │ ────────────────>
     ┌──┴───┐          ┌──┴───┐
     │Client│          │Server│
     └──────┘          └──────┘

A konečně explicitní zápis situace, kdy se zpráva vrátí, tj. jedná se o reakci na zprávu předchozí:

import napkin
 
 
@napkin.seq_diagram()
def client_server_5(c):
    client = c.object('Client')
    server = c.object('Server')
 
    with client:
        with server.SYN():
            c.ret("SYN_ACK")
        server.ACK()

Obrázek 17: Povšimněte si, že odpověď je zobrazena čárkovanou šipky.

Odlišný typ šipky je použit i v textové podobě diagramu:

     ┌──────┐          ┌──────┐
     │Client│          │Server│
     └──┬───┘          └──┬───┘
        │     SYN()      ┌┴┐
        │ ──────────────>│ │
        │                └┬┘
        │     SYN_ACK     │
        │ <─ ─ ─ ─ ─ ─ ─ ─
        │                 │
        │      ACK()      │
        │ ────────────────>
     ┌──┴───┐          ┌──┴───┐
     │Client│          │Server│
     └──────┘          └──────┘

13. Reprezentace několika dotazů v sekvenčním diagramu

Pochopitelně nám nic nebrání použít v jednom diagramu několik dotazů, které například mohou reprezentovat rozdílné chování systému pro různé vstupy. Podívejme se na jeden z možných příkladů – přihlašování uživatele, které může být buď úspěšné nebo naopak neúspěšné:

import napkin
 
 
@napkin.seq_diagram()
def request_response_1(c):
    client = c.object('Client')
    frontend = c.object('"Front end"')
    backend = c.object('"Back end"')
 
    with client:
        with frontend.request("login='foo'", "password='bar'"):
            with backend.try_login("'foo'", "'bar'"):
                c.ret("login ok")
            c.ret("login ok")
 
    with client:
        with frontend.request("login='foo'", "password='xyzzy'"):
            with backend.try_login("'foo'", "'bar'"):
                c.ret("login failed")
            c.ret("login failed")

Výsledek bude vypadat následovně:

Obrázek 18: Diagram vytvořený předchozím příkladem.

Prakticky stejného výsledku dosáhneme i tímto kódem:

import napkin
 
 
@napkin.seq_diagram()
def request_response_2(c):
    client = c.object('Client')
    frontend = c.object('"Front end"')
    backend = c.object('"Back end"')
 
    with client:
        with frontend.request("login='foo'", "password='bar'"):
            with backend.try_login("'foo'", "'bar'"):
                c.ret("login ok")
            c.ret("login ok")
 
        with frontend.request("login='foo'", "password='xyzzy'"):
            with backend.try_login("'foo'", "'bar'"):
                c.ret("login failed")
            c.ret("login failed")

Obrázek 19: Diagram, který by měl být shodný s diagramem předchozím.

V textové podobě bude diagram vypadat takto:

     ┌──────┐                              ┌─────────┐                ┌────────┐
     │Client│                              │Front end│                │Back end│
     └──┬───┘                              └────┬────┘                └───┬────┘
        │ request(login='foo', password='bar') ┌┴┐                        │
        │ ────────────────────────────────────>│ │                        │
        │                                      │ │                        │
        │                                      │ │try_login('foo', 'bar') ┌┴┐
        │                                      │ │ ─────────────────────> │ │
        │                                      │ │                        └┬┘
        │                                      │ │        login ok        │
        │                                      │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
        │                                      └┬┘                        │
        │                login ok               │                         │
        │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │
        │                                       │                         │
        │request(login='foo', password='xyzzy')┌┴┐                        │
        │ ────────────────────────────────────>│ │                        │
        │                                      │ │                        │
        │                                      │ │try_login('foo', 'bar') ┌┴┐
        │                                      │ │ ─────────────────────> │ │
        │                                      │ │                        └┬┘
        │                                      │ │      login failed      │
        │                                      │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
        │                                      └┬┘                        │
        │              login failed             │                         │
        │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │
     ┌──┴───┐                              ┌────┴────┐                ┌───┴────┐
     │Client│                              │Front end│                │Back end│
     └──────┘                              └─────────┘                └────────┘

14. Specifikace opakujících se sekvenčních operací (loop)

Do sekvenčních diagramů lze vložit i symboly reprezentující opakování (loop). V knihovně Napkin je toto chování zajištěno kontextem c.loop():

import napkin
 
 
@napkin.seq_diagram()
def request_response_3(c):
    client = c.object('Client')
    frontend = c.object('"Front end"')
    backend = c.object('"Back end"')
 
    with client:
        with frontend.request("login='foo'", "password='bar'"):
            with backend.try_login("'foo'", "'bar'"):
                c.ret("login ok")
            c.ret("login ok")
 
    with c.loop():
        with client:
            with frontend.request("login='foo'", "password='xyzzy'"):
                with backend.try_login("'foo'", "'bar'"):
                    c.ret("login failed")
                c.ret("login failed")

S výsledkem:

Obrázek 20: Diagram s cyklem.

Textová podoba výsledku:

                    ┌──────┐                              ┌─────────┐                ┌────────┐
                    │Client│                              │Front end│                │Back end│
                    └──┬───┘                              └────┬────┘                └───┬────┘
                       │ request(login='foo', password='bar') ┌┴┐                        │
                       │ ────────────────────────────────────>│ │                        │
                       │                                      │ │                        │
                       │                                      │ │try_login('foo', 'bar') ┌┴┐
                       │                                      │ │ ─────────────────────> │ │
                       │                                      │ │                        └┬┘
                       │                                      │ │        login ok        │
                       │                                      │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
                       │                                      └┬┘                        │
                       │                login ok               │                         │
                       │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │
                       │                                       │                         │
                       │                                       │                         │
          ╔═══════╤════╪═══════════════════════════════════════╪═════════════════════════╪══════════════╗
          ║ LOOP  │    │                                       │                         │              ║
          ╟───────┘    │                                       │                         │              ║
          ║            │request(login='foo', password='xyzzy')┌┴┐                        │              ║
          ║            │ ────────────────────────────────────>│ │                        │              ║
          ║            │                                      │ │                        │              ║
          ║            │                                      │ │try_login('foo', 'bar') ┌┴┐            ║
          ║            │                                      │ │ ─────────────────────> │ │            ║
          ║            │                                      │ │                        └┬┘            ║
          ║            │                                      │ │      login failed      │              ║
          ║            │                                      │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─              ║
          ║            │                                      └┬┘                        │              ║
          ║            │              login failed             │                         │              ║
          ║            │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │              ║
          ╚════════════╪═══════════════════════════════════════╪═════════════════════════╪══════════════╝
                    ┌──┴───┐                              ┌────┴────┐                ┌───┴────┐
                    │Client│                              │Front end│                │Back end│
                    └──────┘                              └─────────┘                └────────┘

15. Vnořené cykly (loop) v diagramu

Cykly mohou být i vnořené. Bez podrobnějších popisů se podívejme na příklad, v němž je naznačeno, že se přihlašovací procedura může opakovat (což sice není příliš logické, ovšem jedná se pouze o ilustrační příklad):

import napkin
 
 
@napkin.seq_diagram()
def request_response_4(c):
    client = c.object('Client')
    frontend = c.object('"Front end"')
    backend = c.object('"Back end"')
 
    with client:
        with frontend.request("login='foo'", "password='bar'"):
            with backend.try_login("'foo'", "'bar'"):
                c.ret("login ok")
            c.ret("login ok")
 
    with c.loop():
        with client:
            with frontend.request("login='foo'", "password='xyzzy'"):
                with c.loop():
                    with backend.try_login("'foo'", "'bar'"):
                        c.ret("login failed")
                    c.ret("login failed")

Obrázek 21: Diagram s vnořenými cykly.

Opět si ukažme textovou podobu diagramu:

                    ┌──────┐                              ┌─────────┐                ┌────────┐
                    │Client│                              │Front end│                │Back end│
                    └──┬───┘                              └────┬────┘                └───┬────┘
                       │ request(login='foo', password='bar') ┌┴┐                        │
                       │ ────────────────────────────────────>│ │                        │
                       │                                      │ │                        │
                       │                                      │ │try_login('foo', 'bar') ┌┴┐
                       │                                      │ │ ─────────────────────> │ │
                       │                                      │ │                        └┬┘
                       │                                      │ │        login ok        │
                       │                                      │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
                       │                                      └┬┘                        │
                       │                login ok               │                         │
                       │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │
                       │                                       │                         │
                       │                                       │                         │
          ╔═══════╤════╪═══════════════════════════════════════╪═════════════════════════╪════════════════════════╗
          ║ LOOP  │    │                                       │                         │                        ║
          ╟───────┘    │                                       │                         │                        ║
          ║            │request(login='foo', password='xyzzy')┌┴┐                        │                        ║
          ║            │ ────────────────────────────────────>│ │                        │                        ║
          ║            │                                      │ │                        │                        ║
          ║            │                                      │ │                        │                        ║
          ║            │                        ╔═══════╤═════╪═╪════════════════════════╪══════════════╗         ║
          ║            │                        ║ LOOP  │     │ │                        │              ║         ║
          ║            │                        ╟───────┘     │ │                        │              ║         ║
          ║            │                        ║             │ │try_login('foo', 'bar') ┌┴┐            ║         ║
          ║            │                        ║             │ │ ─────────────────────> │ │            ║         ║
          ║            │                        ║             │ │                        └┬┘            ║         ║
          ║            │                        ║             │ │      login failed      │              ║         ║
          ║            │                        ║             │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─              ║         ║
          ║            │                        ╚═════════════╪═╪════════════════════════╪══════════════╝         ║
          ║            │                                      └┬┘                        │                        ║
          ║            │              login failed             │                         │                        ║
          ║            │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │                        ║
          ╚════════════╪═══════════════════════════════════════╪═════════════════════════╪════════════════════════╝
                    ┌──┴───┐                              ┌────┴────┐                ┌───┴────┐
                    │Client│                              │Front end│                │Back end│
                    └──────┘                              └─────────┘                └────────┘

16. Seskupení zpráv v diagramu

Cyklům je podobná i značka pro seskupení zpráv v diagramu. V knihovně Napkin se pro tento účel používá konstrukce with c.group(„Popis skupiny“) tak, jak je to naznačeno v dalším (již předposledním) demonstračním příkladu:

import napkin
 
 
@napkin.seq_diagram()
def request_response_5(c):
    client = c.object('Client')
    frontend = c.object('"Front end"')
    backend = c.object('"Back end"')
 
    with c.group("Successful login"):
        with client:
            with frontend.request("login='foo'", "password='bar'"):
                with backend.try_login("'foo'", "'bar'"):
                    c.ret("login ok")
                c.ret("login ok")
 
    with c.group("Failed login"):
        with client:
            with frontend.request("login='foo'", "password='xyzzy'"):
                with c.loop():
                    with backend.try_login("'foo'", "'bar'"):
                        c.ret("login failed")
                    c.ret("login failed")

Obrázek 22: Diagram se seskupenými zprávami.

Opět si ukažme textovou podobu diagramu:

                    ┌──────┐                              ┌─────────┐                ┌────────┐
                    │Client│                              │Front end│                │Back end│
                    └──┬───┘                              └────┬────┘                └───┬────┘
                       │                                       │                         │
          ╔════════════╪══════╤════════════════════════════════╪═════════════════════════╪══════════════╗
          ║ SUCCESSFUL LOGIN  │                                │                         │              ║
          ╟──────────────request(login='foo', password='bar') ┌┴┐                        │              ║
          ║            │ ────────────────────────────────────>│ │                        │              ║
          ║            │                                      │ │                        │              ║
          ║            │                                      │ │try_login('foo', 'bar') ┌┴┐            ║
          ║            │                                      │ │ ─────────────────────> │ │            ║
          ║            │                                      │ │                        └┬┘            ║
          ║            │                                      │ │        login ok        │              ║
          ║            │                                      │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─              ║
          ║            │                                      └┬┘                        │              ║
          ║            │                login ok               │                         │              ║
          ║            │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │              ║
          ╚════════════╪═══════════════════════════════════════╪═════════════════════════╪══════════════╝
                       │                                       │                         │
                       │                                       │                         │
          ╔════════════╪══╤════════════════════════════════════╪═════════════════════════╪════════════════════════╗
          ║ FAILED LOGIN  │                                    │                         │                        ║
          ╟─────────────request(login='foo', password='xyzzy')┌┴┐                        │                        ║
          ║            │ ────────────────────────────────────>│ │                        │                        ║
          ║            │                                      │ │                        │                        ║
          ║            │                                      │ │                        │                        ║
          ║            │                        ╔═══════╤═════╪═╪════════════════════════╪══════════════╗         ║
          ║            │                        ║ LOOP  │     │ │                        │              ║         ║
          ║            │                        ╟───────┘     │ │                        │              ║         ║
          ║            │                        ║             │ │try_login('foo', 'bar') ┌┴┐            ║         ║
          ║            │                        ║             │ │ ─────────────────────> │ │            ║         ║
          ║            │                        ║             │ │                        └┬┘            ║         ║
          ║            │                        ║             │ │      login failed      │              ║         ║
          ║            │                        ║             │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─              ║         ║
          ║            │                        ╚═════════════╪═╪════════════════════════╪══════════════╝         ║
          ║            │                                      └┬┘                        │                        ║
          ║            │              login failed             │                         │                        ║
          ║            │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │                        ║
          ╚════════════╪═══════════════════════════════════════╪═════════════════════════╪════════════════════════╝
                    ┌──┴───┐                              ┌────┴────┐                ┌───┴────┐
                    │Client│                              │Front end│                │Back end│
                    └──────┘                              └─────────┘                └────────┘

17. Poznámky přiřazené k uzlům, zprávám či skupinám

Poslední vlastností knihovny Napkin, kterou si dnes ukážeme, je možnost přidat poznámky (komentáře) k uzlům, zprávám popř. skupinám. Prakticky každý objekt, s nímž se v knihovně Napkin pracuje, poskytuje metodu note pro přidání poznámky (viz zvýrazněné části skriptu):

import napkin
 
 
@napkin.seq_diagram()
def request_response_6(c):
    client = c.object('Client')
    frontend = c.object('"Front end"')
    backend = c.object('"Back end"')
 
    client.note("Web client")
    frontend.note("Web front end (JS)")
    backend.note("Back end (Go)")
 
    with c.group("Successful login"):
        with client:
            c.note("Login with proper name and password")
            with frontend.request("login='foo'", "password='bar'").note("Correct password"):
                with backend.try_login("'foo'", "'bar'"):
                    c.ret("login ok")
                c.ret("login ok")
 
    with c.group("Failed login"):
        with client:
            c.note("Login with improper name and password")
            with frontend.request("login='foo'", "password='xyzzy'").note("Bad password"):
                with c.loop():
                    with backend.try_login("'foo'", "'bar'"):
                        c.ret("login failed")
                    c.ret("login failed")
                    c.note("Trying again ... is meaningless")

Obrázek 23: Diagram s přidanými poznámkami.

Poznámky se pochopitelně objeví i v textovém výstupu:

CS24 tip temata

                                 ┌──────┐                              ┌─────────┐                ┌────────┐
                                 │Client│                              │Front end│                │Back end│
                                 └──┬───┘                              └────┬────┘                └───┬────┘
                              ╔═════╧══════╗                                │                         │
                              ║Web client ░║                                │                         │
                              ╚═════╤══════╝                                │                         │
                                    │                             ╔═════════╧══════════╗              │
                                    │                             ║Web front end (JS) ░║              │
                                    │                             ╚═════════╤══════════╝              │
                                    │                                       │                  ╔══════╧════════╗
                                    │                                       │                  ║Back end (Go) ░║
                                    │                                       │                  ╚══════╤════════╝
                                    │                                       │                         │
           ╔═══════════════════╤════╪═══════════════════════════════════════╪═════════════════════════╪══════════════╗
           ║ SUCCESSFUL LOGIN  │    │                                       │                         │              ║
           ╟──────╔═════════════════╧═══════════════════╗                   │                         │              ║
           ║      ║Login with proper name and password ░║                   │                         │              ║
           ║      ╚═════════════════╤═══════════════════╝                   │                         │              ║
           ║                        │ request(login='foo', password='bar') ┌┴┐  ╔══════════════════╗  │              ║
           ║                        │ ────────────────────────────────────>│ │  ║Correct password ░║  │              ║
           ║                        │                                      │ │  ╚══════════════════╝  │              ║
           ║                        │                                      │ │try_login('foo', 'bar') ┌┴┐            ║
           ║                        │                                      │ │ ─────────────────────> │ │            ║
           ║                        │                                      │ │                        └┬┘            ║
           ║                        │                                      │ │        login ok        │              ║
           ║                        │                                      │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─              ║
           ║                        │                                      └┬┘                        │              ║
           ║                        │                login ok               │                         │              ║
           ║                        │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │              ║
           ╚════════════════════════╪═══════════════════════════════════════╪═════════════════════════╪══════════════╝
                                    │                                       │                         │
                                    │                                       │                         │
          ╔═══════════════╤═════════╪═══════════════════════════════════════╪═════════════════════════╪════════════════════════╗
          ║ FAILED LOGIN  │         │                                       │                         │                        ║
          ╟──────╔══════════════════╧════════════════════╗                  │                         │                        ║
          ║      ║Login with improper name and password ░║                  │                         │                        ║
          ║      ╚══════════════════╤════════════════════╝                  │                         │                        ║
          ║                         │request(login='foo', password='xyzzy')┌┴┐  ╔══════════════╗      │                        ║
          ║                         │ ────────────────────────────────────>│ │  ║Bad password ░║      │                        ║
          ║                         │                                      │ │  ╚══════════════╝      │                        ║
          ║                         │                                      │ │                        │                        ║
          ║                         │                ╔═══════╤═════════════╪═╪════════════════════════╪══════════════╗         ║
          ║                         │                ║ LOOP  │             │ │                        │              ║         ║
          ║                         │                ╟───────┘             │ │                        │              ║         ║
          ║                         │                ║                     │ │try_login('foo', 'bar') ┌┴┐            ║         ║
          ║                         │                ║                     │ │ ─────────────────────> │ │            ║         ║
          ║                         │                ║                     │ │                        └┬┘            ║         ║
          ║                         │                ║                     │ │      login failed      │              ║         ║
          ║                         │                ║                     │ │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─              ║         ║
          ║                         │                ║                     │ │                        │              ║         ║
          ║                         │                ║      ╔══════════════╧═╧════════════════╗       │              ║         ║
          ║                         │                ║      ║Trying again ... is meaningless ░║       │              ║         ║
          ║                         │                ╚══════╚═════════════════════════════════╝═══════╪══════════════╝         ║
          ║                         │                                      └┬┘                        │                        ║
          ║                         │              login failed             │                         │                        ║
          ║                         │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                          │                        ║
          ╚═════════════════════════╪═══════════════════════════════════════╪═════════════════════════╪════════════════════════╝
                                 ┌──┴───┐                              ┌────┴────┐                ┌───┴────┐
                                 │Client│                              │Front end│                │Back end│
                                 └──────┘                              └─────────┘                └────────┘

18. Repositář s demonstračními příklady

Zdrojové kódy všech dnes popsaných demonstračních příkladů určených pro Python 3 byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Demonstrační příklad Stručný popis příkladu Cesta
1 client-server-1.py diagram se dvěma komunikujícími objekty a jednou poslanou zprávou https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-1.py
2 client-server-1.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-1.puml
3 client-server-1.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-1.txt
       
4 client-server-2.py nepatrně složitější diagram: three-way handshake https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-2.py
5 client-server-2.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-2.puml
6 client-server-2.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-2.txt
       
7 client-server-3.py zobrazení doby zpracování popř. čekání na odpověď, první varianta https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-3.py
8 client-server-3.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-3.puml
9 client-server-3.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-3.txt
       
10 client-server-4.py zobrazení doby zpracování popř. čekání na odpověď, druhá varianta https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-4.py
11 client-server-4.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-4.puml
12 client-server-4.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-4.txt
       
13 client-server-5.py zobrazení doby zpracování popř. čekání na odpověď, třetí varianta https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-5.py
14 client-server-5.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-5.puml
15 client-server-5.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/client-server-5.txt
       
16 request-response-1.py reprezentace několika dotazů v sekvenčním diagramu, první varianta https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-1.py
17 request-response-1.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-1.puml
18 request-response-1.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-1.txt
       
19 request-response-2.py reprezentace několika dotazů v sekvenčním diagramu, druhá varianta https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-2.py
20 request-response-2.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-2.puml
21 request-response-2.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-2.txt
       
22 request-response-3.py specifikace opakujících se sekvenčních operací (loop) https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-3.py
23 request-response-3.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-3.puml
24 request-response-3.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-3.txt
       
25 request-response-4.py vnořené cykly (loop) v diagramu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-4.py
26 request-response-4.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-4.puml
27 request-response-4.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-4.txt
       
28 request-response-5.py seskupení zpráv v diagramu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-5.py
29 request-response-5.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-5.puml
30 request-response-5.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-5.txt
       
31 request-response-6.py poznámky přiřazené k uzlům, zprávám či skupinám https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-6.py
32 request-response-6.puml diagram zapsaný ve formátu PlantUML https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-6.puml
33 request-response-6.txt diagram převedený do ASCII artu https://github.com/tisnik/most-popular-python-libs/blob/master/napkin/request-response-6.txt

19. Odkazy na články s tématem programové tvorby grafů a diagramů

V této kapitole jsou uvedeny odkazy na předchozí články, v nichž jsme se zabývali tvorbou různých typů grafů a diagramů – a to v naprosté většině případů s využitím nějakého doménově specifického jazyka neboli DSL (Domain Specific Language) popř. nějakého univerzálního programovacího jazyka:

  1. Nástroje pro tvorbu UML diagramů
    https://www.root.cz/clanky/nastroje-pro-tvorbu-uml-diagramu/
  2. Nástroje pro tvorbu UML diagramů z příkazové řádky
    https://www.root.cz/clanky/nastroje-pro-tvorbu-uml-diagramu-z-prikazove-radky/
  3. Nástroje pro tvorbu UML diagramů z příkazové řádky (II)
    https://www.root.cz/clanky/nastroje-pro-tvorbu-uml-diagramu-z-prikazove-radky-ii/
  4. Nástroje pro tvorbu grafů a diagramů z příkazové řádky
    https://www.root.cz/clanky/nastroje-pro-tvorbu-grafu-a-diagramu-z-prikazove-radky/
  5. Sledování správy paměti v Pythonu s využitím nástroje objgraph
    https://www.root.cz/clanky/sledovani-spravy-pameti-v-pythonu-s-vyuzitim-nastroje-objgraph/
  6. Programová tvorba diagramů v jazyku Clojure s využitím knihovny Rhizome
    https://www.root.cz/clanky/programova-tvorba-diagramu-v-jazyku-clojure-s-vyuzitim-knihovny-rhizome/

20. Odkazy na Internetu

  1. Napkin na GitHubu
    https://github.com/pinetr2e/napkin
  2. Napkin 0.6.8 na PyPi
    https://pypi.org/project/napkin/
  3. PlantUML (home page)
    http://plantuml.sourceforge.net/
  4. PlantUML (download page)
    http://sourceforge.net/pro­jects/plantuml/files/plan­tuml.jar/download
  5. PlantUML (Language Reference Guide)
    http://plantuml.sourcefor­ge.net/PlantUML_Language_Re­ference_Guide.pdf
  6. Rhizome
    https://github.com/ztellman/rhizome
  7. Swagger to UML
    https://github.com/nlohman­n/swagger_to_uml
  8. pydiagrams
    https://github.com/billin­gtonm/pydiagrams
  9. graphviz(3) – Linux man page
    https://linux.die.net/man/3/graphviz
  10. dot(1) – Linux man page
    https://linux.die.net/man/1/dot
  11. neato(1) – Linux man page
    https://linux.die.net/man/1/neato
  12. twopi(1) – Linux man page
    https://linux.die.net/man/1/twopi
  13. circo(1) – Linux man page
    https://linux.die.net/man/1/circo
  14. fdp(1) – Linux man page
    https://linux.die.net/man/1/fdp
  15. sfdp(1) – Linux man page
    https://linux.die.net/man/1/sfdp
  16. Plain-text diagrams take shape in Asciidoctor!
    http://asciidoctor.org/new­s/2014/02/18/plain-text-diagrams-in-asciidoctor/
  17. Graphviz – Graph Visualization Software
    http://www.graphviz.org/
  18. graphviz (Manual Page)
    http://www.root.cz/man/7/graphviz/
  19. dot (Manual page)
    http://www.root.cz/man/1/dot/
  20. dot (Manual v PDF)
    https://graphviz.org/pdf/dot.1.pdf
  21. Ditaa home page
    http://ditaa.sourceforge.net/
  22. Ditaa introduction
    http://ditaa.sourceforge.net/#intro
  23. Ditaa usage
    http://ditaa.sourceforge.net/#usage
  24. Node, Edge and Graph Attributes
    http://www.graphviz.org/doc/in­fo/attrs.html
  25. Graphviz (Wikipedia)
    http://en.wikipedia.org/wiki/Graphviz
  26. Unified Modeling Language
    https://en.wikipedia.org/wi­ki/Unified_Modeling_Langu­age
  27. UML basics: The sequence diagram
    http://www.ibm.com/develo­perworks/rational/library/3101­.html
  28. UML 2 State Machine Diagrams: An Agile Introduction
    http://www.agilemodeling.com/ar­tifacts/stateMachineDiagram­.htm
  29. Sequence diagram (Wikipedia)
    https://en.wikipedia.org/wi­ki/Sequence_diagram
  30. UML 2 Sequence Diagrams: An Agile Introduction
    http://www.agilemodeling.com/ar­tifacts/sequenceDiagram.htm
  31. A Quick Introduction to UML Sequence Diagrams
    http://www.tracemodeler.com/ar­ticles/a_quick_introducti­on_to_uml_sequence_diagram­s/
  32. UML Sequence Diagrams
    https://www.uml-diagrams.org/sequence-diagrams.html
  33. Web Sequence Diagrams
    https://www.websequencediagrams.com/
  34. Drawing sequence diagrams “napkin style”
    https://modeling-languages.com/drawing-sequence-diagrams-napkin-style/
  35. Curated list of UML tools – 2020 edition
    https://modeling-languages.com/uml-tools/#textual
  36. Flowchart diagrams vs. UML activity diagrams
    https://stackoverflow.com/qu­estions/7081215/flowchart-diagrams-vs-uml-activity-diagrams
  37. Kopenograms – Graphical Language for Structured Algorithms
    https://kopenogram.org/As­sets/Kopenograms_Graphical_Lan­guage_for_Structured_Algo­rithms.pdf

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.