UML (Unified Modeling Language) is an ISO standardized method for describing programs. Its resulting diagrams are widely taught and should therefore be used as much as possible. The standard is mostly about the inner mechanism of the modeling language and not so much about the diagrams, however, the diagrams are the most useful part, as they are quickly understood even by non-programmers.
Check out these web-sites
This is the inheritance hierarchy of UML diagrams supported by PlantUML (clickable in HTML):
The site UML tools : Curated selection of free, online, OSS, for MAC,… tools is an extensive collection of UML tool information.
Many UML tools specialize in providing a GUI environment to design diagrams with extensive support for a detailed standards-compliant specification of elements. The output is standardized but unreadable XMI (XML Metadata Interchange). This disqualifies most of the UML GUI tools for proper adhoc ASCII level documentation.
Creating unreadable diagram defintions, which require HTML/PDF/image generation before they become useful is highly undesirable if your focus is on programming. The incentive for a programmer to keep the documentation up to date is negative[1].
GUI Tools are still useful to explore the graphical notation of the various diagrams. See ref:gui tools with uml standard support.
If your focus is on modeling, the UML GUI Tools are a better choice, but if your main task is programming, this is the way to go. The introduction to UMLGraph provides an excellent argument for declarative specification of UML diagrams.
The Stack Overflow question “Generating UML diagrams from textual representation” references a list of tools (Text to UML tools), but highlights PlantUML.
The PlantUML tool’s definition language is quite readable without the rendered diagrams. It also integrates with many tools (namely Emacs and Sphinx)- (See section Sequence Diagram). The GitHubGist generate PlantUML definition from python sources provides genclass.py, locally renamed to gen_plantuml.py. This command helps with the initial UML class diagrams and further updates. See section Auto generators for an example generator of a class diagram for global variables/functions.
yUML has sphinx integration, but is very limited in regarding readability and choice of diagrams (see section yUML).
Umple: Merging Modeling with Programming, i.e. it works as a programming language pre-processor (programming language extension, roundtrip).
The most important UML Diagrams are
Use case diagrams are usually referred to as behavior diagrams used to describe a set of actions (use cases) that some system or systems (subject) should or can perform in collaboration with one or more external users of the system (actors). Each use case should provide some observable and valuable result to the actors or other stakeholders of the system. (https://www.uml-diagrams.org/use-case-diagrams.html)
Here is the use case diagram of a workers day:
.. uml::
@startuml
worker1 -> (work)
worker2 -> (work)
worker1 -> (home1)
worker2 -> (home2)
@enduml
This is how it is rendered in Sphinx:
For details see PlantUML Language Reference Guide.
Class diagram is UML structure diagram which shows structure of the designed system at the level of classes and interfaces, shows their features, constraints and relationships - associations, generalizations, dependencies, etc. (https://www.uml-diagrams.org/class-diagrams-overview.html)
PlantUML example (PlantUML Language Reference Guide):
.. uml::
@startuml
class OneClass {
-private : string
+public : int
-priv_method()
+pub_method()
}
' stereotype
class TwoClass << (I, #ffcccc) interface >>
OneClass ..|> TwoClass
hide TwoClass members
@enduml
This is how it is rendered in Sphinx:
UML association is relationship between classifiers to show that instances of classifiers could be either linked to each other or combined into some aggregation. See the definitive Guide to UML associations.
Association: | is a relationship where all objects have their own lifecycle and there is no owner. Let’s take an example of Teacher and Student. Multiple students can associate with single teacher and single student can associate with multiple teachers, but there is no ownership between the objects and both have their own lifecycle. Both can be created and deleted independently. |
---|---|
Aggregation: | is a specialised form of Association where all objects have their own lifecycle, but there is ownership and child objects can not belong to another parent object. Let’s take an example of Department and teacher. A single teacher can not belong to multiple departments, but if we delete the department, the teacher object will not be destroyed. We can think about it as a “has-a” relationship. |
Composition: | is again specialised form of Aggregation and we can call this as a “death” relationship. It is a strong type of Aggregation. Child object does not have its lifecycle and if parent object is deleted, all child objects will also be deleted. Let’s take again an example of relationship between House and Rooms. House can contain multiple rooms - there is no independent life of room and any room can not belong to two different houses. If we delete the house - room will automatically be deleted. Let’s take another example relationship between Questions and Options. Single questions can have multiple options and option can not belong to multiple questions. If we delete the questions, options will automatically be deleted. |
Source: StackExchange
PlantUML offers various association types:
Relation | Symbol | Description |
---|---|---|
Association | -- |
no owner, navigability unspecified |
Directed Association | <-- |
no owner, navigable |
Association | x-- |
no owner, not navigable |
Aggregation | o-- |
owner, but independent |
Composition | *-- |
owner and dependent |
Dependency | <.. |
no owner |
Generalization/Extension | <│-- |
|
Realization | <│.. |
|
Nesting | +-- |
It is possible to replace --
by ..
for broken lines.
Naming conventions, visibility and types in global namespace and within classes:
Enums can be used to describe variable collections:
Here is a more elaborate class diagram in _static/big-brother.puml
:
@startuml
!include ws-cartoon-logo.puml
class "<$ws> BigBrother" as BB {
who[]
who_not[]
--
watch_em() : who
check_em() : who_not
..
check(p) : suspect/vindicate
watch(p,time) : boring/strange
suspect(p) : move //p// from //who_not// to //who//
vindicate(p) : move //p// from //who// to //who_not//
}
hide BB circle
@enduml
It can be included with the uml directive:
.. uml:: _static/big-brother.puml
:caption: Big Brother is watching you
or specify path to external PlantUML file:
You can specify height, width, scale and align:
You can specify a caption:
|:todo:| describe uml directive explicitely
If the uml directive has a caption (via option :caption:), it behaves like the figure directive. Otherwise, it behaves like the image directive.
Activity diagram is UML behavior diagram which shows flow of control or object flow with emphasis on the sequence and conditions of the flow. The actions coordinated by activity models can be initiated because other actions finish executing, because objects and data become available, or because some events external to the flow occur. (https://www.uml-diagrams.org/activity-diagrams.html)
Note
It is not a data flow diagram!
See State Machine Diagram vs Activity Diagram for a basic explanation of the differences.
Here is the activity diagram of a persons daily routine:
.. uml::
@startuml
!include _static/call-bevahor.puml
start
:alarm clock rings;
:turn off the alarm clock;
if(is it weekend?) then (yes)
:go back to sleep;
else (no)
:eat;
:wash;
:CALL(go to work);
endif
stop
@enduml
This is how it is rendered in Sphinx:
For details see PlantUML Language Reference Guide.
Here is the activity diagram to check a person BB.check(person):
Another activity Diagram:
State machine diagram is a behavior diagram which shows discrete behavior of a part of designed system through finite state transitions. State machine diagrams can also be used to express the usage protocol of part of a system. (https://www.uml-diagrams.org/state-machine-diagrams.html)
Here is the State Machine Diagram of the procedure of starting a software project:
.. uml::
@startuml
state plan as "Planning Project"
plan : identify necessary UML diagram
state create as "Create UML Diagram"
state draw as "Draw UML Diagram"
draw : modify diagram
state bless as "Blessing"
bless : discuss UML Diagram with boss
state coding as "Programming"
state doc as "Document"
[*] --> plan
plan --> bless : finished
create --> draw
draw --> bless
bless --> plan : missing diagram
bless --> plan : superfluous diagram
bless --> create : new diagram\nblessed
bless --> draw : error in\ndiagram
bless --> coding : all diagrams\nfinished
coding --> doc : new object
doc --> coding : finished
doc --> plan : missing diagram
coding --> [*]
@enduml
This is how it is rendered in Sphinx:
See Choice Pseudostate and Guard Condition in State Diagrams for additional state diagram syntax:
@startuml
left to right direction
state choice <<choice>>
state alt
state fork <<fork>>
state p1
state p2
state join <<join>>
state end <<end>>
[*] --> choice
choice --> alt
alt --> fork
choice --> fork
fork --> p1
fork --> p2
p1 --> join
p2 --> join
join --> end
@enduml
rendered as:
Sequence diagram is the most common kind of interaction diagram, which focuses on the message interchange between a number of lifelines.
Sequence diagram describes an interaction by focusing on the sequence of messages that are exchanged, along with their corresponding occurrence specifications on the lifelines. (https://www.uml-diagrams.org/sequence-diagrams.html)
Here is the sequence diagram of a short conversation between me and my boss:
.. uml::
Dominik -> Wolfgang : Am I doing\nit correctly?
Wolfgang -> Dominik : Nice try\ndo it again!
This is how it is rendered in Sphinx:
For details see PlantUML Language Reference Guide.
PlantUML is (in its own words) an
open-source tool that uses simple textual descriptions to draw UML diagrams.
See also sections PlantUML Installation and PlantUML Emacs Mode below.
The PlantUML Language Reference Guide
is available locally
and describes the standard PlantUML diagrams. However, some diagrams
are only explained at the PlantUML web site.
Since PlantUML is the standard documentation tool for UML diagrams, specifying diagrams is explained, where the UML diagrams are described.
Here are just some experiments with special diagram types.
Salt is meant for GUI specifications:
PlantUML is available as a ubuntu package:
apt-get install plantuml
Besides numerous other integrations there is also a sphinx extension module available:
apt-get install python-sphinxcontrib.plantuml
apt-get install python3-sphinxcontrib.plantuml
The standard ubuntu packages are too old (sphinx: 0.5)! Use the backported versions (sphinx: 0.11) which are available in the local repository:
deb [trusted=yes] http://scherer.wiedenmann.intern/repository xenial main
deb-src [trusted=yes] http://scherer.wiedenmann.intern/repository xenial main
There is also a major mode for editing PlantUML sources in Emacs with preview facilities:
wget https://raw.githubusercontent.com/skuro/plantuml-mode/master/plantuml-mode.el
This mode is included in the local shared site-lisp.
You can automatically enable plantuml-mode
for files with extension
.plantuml
by adding the following to your .emacsrc
:
;; Enable plantuml-mode for `PlantUML`_ files
(add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode))
Of course, you can always enable manually the major mode by typing
M-x plantuml-mode
once in the desired PlantUML file buffer.
You can tell plantuml-mode
to autocomplete the word before the
cursor by typing M-x plantuml-complete-symbol
. This will open a
popup with all the available completions as found in the list of
keywords given by running PlantUML with the -language
flag.
To render the PlantUML diagram within Emacs, you can hit
M-x plantuml-preview
. This will run plantuml(1) and display the result
in the *PLANTUML-Preview*
buffer. The format used to render the
diagram is automagically chosen from what’s supported by your Emacs. It
will be one of the following, in order of preference:
The diagram will be either created from the selected region if one is available in the current buffer, or using the whole buffer otherwise.
If you want to force a specific output format, you can customize the
variable plantuml-output-type
to the value you prefer.
The following shortcuts are enabled by default:
C-c C-c plantuml-preview: renders a PlantUML diagram from the current buffer in the best supported format
C-u C-c C-c plantuml-preview in other window
C-u C-u C-c C-c plantuml-preview in other frame
The python module UML annotations - line_diversion extracts marked annotation lines from source files.
yUML is a web service only, which makes it hard to use offline.
There is an unofficial command line tool for yuml and sphinx integration sphinxcontrib-yuml.
GitHub - aivarsk/scruffy is an abandoned project that does not use the web service.
yUML provides support for class, activity and usecase diagrams:
.. yuml::
:alt: [Customer]->[Orders]
:type: class, activity or usecase
:scale: positive integer value
:direction: LR, TD or RL (ignored by usecase and activity)
:style: nofunky, plain, scruffy
[Customer|-forname:string;surname:string|doShiz()]<>-orders*>[Order]
[Order]-[note:Aggregate root (nofunky){bg:wheat}]
yUML command line tool:
easy_install git://github.com/wandernauta/yuml
The updated package python-sphinxcontrib.yuml is in the local package repository and can be installed with:
apt-get install python-sphinxcontrib.yuml
See also njouanin/sphinxcontrib-yuml;
Manual installation from original sources:
wget -q 'https://pypi.python.org/packages/bf/9b/99d1ea03b6199ccd93fbf19b02fe23160b0004b6973d4bd1ef233bd633e2/sphinxcontrib-yuml-0.3.1.tar.gz'
tar -zxf sphinxcontrib-yuml-0.3.1.tar.gz
(
cd sphinxcontrib-yuml-0.3.1/sphinxcontrib/ || exit 1
patch -p0 <<'EOF'
diff -u yuml.orig.py yuml.py
--- yuml.orig.py 2013-11-19 22:08:16.000000000 +0100
+++ yuml.py 2018-04-09 10:47:29.740133938 +0200
@@ -15,6 +15,7 @@
from os import path
from docutils import nodes
from docutils.parsers.rst import directives
+import docutils.parsers.rst.directives.images
from sphinx.errors import SphinxError
from sphinx.util import ensuredir, relative_uri
try:
@@ -48,13 +49,13 @@
:type: class, activity or usecase
:scale: positive integer value
:direction: LR, TD or RL
- :style: boring, plain, scruffy
+ :style: nofunky, plain, scruffy
[Customer]->[Billing Address]
"""
type_values = ('class', 'activity', 'usecase')
direction_values = ('LR', 'RL', 'TD')
- style_values=('boring', 'plain', 'scruffy')
+ style_values=('nofunky', 'plain', 'scruffy')
def type_choice(argument):
return directives.choice(argument, YumlDirective.type_values)
EOF
cp yuml.py /usr/lib/python2.7/dist-packages/sphinxcontrib/
)
Other interesting UML tools by category.
According to the list of Unified Modeling Language tools on Wikipedia, The most recently active projects are
UML Designer (Eclipse) best handling
Papyrus (Eclipse)
BOUML - a free UML tool box has a python generator (free of use)
Modelio Open Source - UML and BPMN free modeling tool (no SVG?)
Umbrello (package Umbrello)
UMLet (package umlet)
Freeform diagrams, proprietary XML file format, image export. Java auto generator support.
ArgoUML (UML 1.4)
Dia (package dia),
Freeform diagrams, proprietary compressed XML format. Image, dot, Visio export.
gen_plantuml.py based on the GitHubGist generate PlantUML definition from python sources.
pyreverse (from package pylint),
python -> dot.
Generating a PlantUML definition of global variables and functions can also be as simple as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | class_name = 'global'
func_type = type(run)
func_type_builtin = type(issequence)
module_type = type(os)
globals_ = globals()
public = globals_.get('__all__', [])
if not public:
public = list(dkeys(globals_))
items = []
items.extend(((_sym, _val, '-') for _sym, _val in sorted(ditems(globals_)) if _sym not in public))
items.extend(((_sym, globals_[_sym], '+') for _sym in public))
opt_all_syms = None
classes = []
variables = []
functions = []
for _sym, _val, _visibility in items:
if not opt_all_syms:
if _sym.startswith('_'):
continue
if _sym.startswith('__') and _sym.endswith('__'):
continue
if isinstance(_val, module_type):
continue
if isinstance(_val, type):
classes.append((_sym, _val, _visibility))
continue
if isinstance(_val, (func_type, func_type_builtin)):
_list = functions
_sfx = '()'
else:
_list = variables
_sfx = ''
_list.append(sformat('{0} : {1}{2}{3}', class_name, _visibility, _sym, _sfx))
printf(sformat(' class {0} << (G, #FFCCCC) >>', class_name))
for _list in variables, functions:
printf('\n'.join((' ' + _e for _e in _list)))
|
Or as fancy as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | PARENTHESES = dict((
('(', ')'),
('[', ']'),
('{', '}'),
('<', '>'),
('<<', '>>'),
('|', '|'),
(' ', ' '),
('"', '"'),
("'", "'"),
))
__all__.append('enclose')
def enclose(elt, open=None, close=None, sep=None, forced=None): # ||:fnc:||
r"""enclose string in parenthesis.
:returns: enclosed string
:param elt: element to be enclosed
:param open: opening parenthesis (default: `(`)
:param close: closing parenthesis (default: :data:`PARENTHESIS`.get(open, '')
:param sep: separator after open and before close, (default: '')
:param forced: add parentheses, even if they already exist.
>>> printf(enclose('abc'))
(abc)
>>> printf(enclose('(abc'))
(abc)
>>> printf(enclose('abc)'))
(abc)
>>> printf(enclose('(abc)'))
(abc)
>>> printf(enclose('(abc)', forced=True))
((abc))
>>> printf(enclose('abc', '<<'))
<<abc>>
>>> printf(enclose(enclose('abc', ' '), '<<'))
<< abc >>
>>> printf(enclose('abc', '-| '))
-| abc
"""
if open is None:
open = '('
if close is None:
close = PARENTHESES.get(open, '')
if sep is None:
sep = ''
enclosed = []
if forced or (open and not re.match('\\s*' + re.escape(open), elt)):
enclosed.append(open)
if open:
enclosed.append(sep)
enclosed.append(elt)
if forced or (close and not re.search(re.escape(close) + '\\s*$', elt)):
if close:
enclosed.append(sep)
enclosed.append(close)
return ''.join(enclosed)
__all__.append('join_lists_flatten')
def join_lists_flatten(lists, sep): # ||:fnc:||
r"""Insert separator between elements of a list.
:returns: list where each group of elements is separated from the next
group of element with `sep`.
:param lists: a list of element groups (lists). All elements of
group are appended as single elements to the result list.
:param sep: separater inserted betwwen two groups of elements.
"""
result = []
if lists:
result.extend(lists[0])
for _list in lists[1:]:
result.append(sep)
result.extend(_list)
return result
__all__.append('plantuml_format_class')
def plantuml_format_class(name, sections=None, circle=None, stereotype=None, alias=None, sep=None): # ||:fnc:||
r"""
:returns: class formatted for a `PlantUML`_ class diagram.
:param name: class name
:param sections: list of class sections, each section is a list of attribute/operation lines.
:param circle:
:param stereotype:
:param alias: class alias
.. _`PlantUML`: http://plantuml.com
"""
if sections is None:
sections = []
formatted = []
_class_param = []
if circle and circle.strip():
_class_param.append(enclose(circle, '('))
if stereotype and stereotype.strip():
_class_param.append(stereotype)
class_param = ' '.join(_class_param)
if class_param:
class_param = enclose(class_param, '<<', sep=' ')
if alias:
name = enclose(name, '"')
class_alias = 'as ' + alias
else:
class_alias = ''
if sep is None:
sep = ''
formatted.append(sformat('class {0} {{', ' '.join((_s for _s in (name, class_alias, class_param) if _s))))
_first = True
for _list in sections:
if _list:
if _first:
_first = False
else:
formatted.append(' ' + sep)
formatted.extend((' ' + _e for _e in _list))
formatted.append('}')
return '\n'.join(formatted)
class_name = 'global'
func_type = type(run)
func_type_builtin = type(issequence)
module_type = type(os)
globals_ = globals()
public = globals_.get('__all__', [])
if not public:
public = list(dkeys(globals_))
items = []
items.extend(((_sym, _val, '-') for _sym, _val in sorted(ditems(globals_)) if _sym not in public))
items.extend(((_sym, globals_[_sym], '+') for _sym in public))
opt_all_syms = None
import pyjsmo
classes = []
variables = pyjsmo.OrderedDict((
('-', []),
('+', []),
))
functions = pyjsmo.OrderedDict((
('-', []),
('+', []),
))
for _sym, _val, _visibility in items:
if not opt_all_syms:
if _sym.startswith('_'):
continue
if _sym.startswith('__') and _sym.endswith('__'):
continue
if isinstance(_val, module_type):
continue
if isinstance(_val, type):
classes.append((_sym, _val, _visibility))
continue
if isinstance(_val, (func_type, func_type_builtin)):
_list = functions[_visibility]
_sfx = '()'
else:
_list = variables[_visibility]
_sfx = ''
_list.append(sformat('{0}{1}{2}', _visibility, _sym, _sfx))
variables = join_lists_flatten([_v for _v in dvalues(variables) if _v], '..')
functions = join_lists_flatten([_v for _v in dvalues(functions) if _v], '..')
printf(plantuml_format_class(class_name, (variables, functions), circle='G, #FFCCCC', sep='--', alias='G'))
|
UML is the abbreviation of unified modeling language. It is a standarizied method for descriping programms.
The UML diagrams are easy to understand even for noprogrammers
There are existing some UML GUI-TOOLS. There are good for noprogrammers to modeling something, but programmers should’nt use them, because the not-diagram-output is’nt readable for a human. And if the output is not readable, it needs more effort to write or update a documentation (you would need every time this GUI-Tool if you want to know what happends in the programm via UML, without the GUI-TOOL, the output is worthless)
Programmers should use PlantUML to create UML diagrams.
A class diagram (similar to entity relationship diagrams for databases) shows boxes for class, interface, annotation, enum, …
The upper section shows attributes, the lower section contains operations (methods).
Sequence Diagram
Shows the message flow between several participants of a system on timelines.
Activity Diagram (in German known as “Aktivitätsdiagramm”)