├── README.md
├── images
├── example-01.svg
├── example-02.svg
├── handcrafted-code-map-andy.png
├── handcrafted-screenshot-based-code-map-andy.jpg
├── literate-drawio-vscode-01.gif
├── literate-drawio-vscode-01.png
└── renaming.drawio
└── plantuml
├── basic-codemap.puml
├── basic-uml.puml
├── example-01.puml
├── example-02.puml
├── html-example.puml
├── numbered-steps.puml
└── python-module.puml
/README.md:
--------------------------------------------------------------------------------
1 | # Literate Code Maps
2 |
3 | *Diagramming Methodology Specification - version 1.0 - Author: Andy Bulka*
4 |
5 | Literate Code Maps are diagrams which help programmers understand the structure and behaviour of source code. Based on, but more practical than UML.
6 |
7 | Code Map diagrams differ from UML diagrams in that they
8 | focus on real source code fragments and lots of
9 | rich-text formatted story-telling narrative.
10 | They combine class and sequence diagrams into the same
11 | diagram, offering step by step numbering to follow the behaviour of a use case story.
12 |
13 | > Literate Code Maps - are not to be confused with the Code Map feature of Visual Studio Enterprise. Literate Code Maps are a free and open diagramming methodology. Visual Studio Code Maps is an interactive code relationship analysis tool reserved for Microsoft languages and customers.
14 |
15 | ## The 5 laws of literate code mapping
16 |
17 | 1. Boxes represent any scope or namespace - be creative
18 | 1. Show structure and behaviour in the same diagram
19 | 1. Code compartments in boxes contain code fragments and richly formatted narrative
20 | 1. Lines representing function calls between boxes are numbered to tell a story
21 | 1. Cross reference numbers can appear anywhere to associate ideas
22 |
23 | Think of literate code maps like UML class diagrams where the classes are now boxes which can represent more things, and lines represent function calls as well as structure. Boxes contain one or more extra compartments containing real code fragments and rich narrative.
24 |
25 | # Quick Intro
26 |
27 | ## The secret behind being *Literate*
28 |
29 | Perhaps you have heard of the saying:
30 |
31 | > *Homines dum docent discunt* — Men learn while they teach. - [Seneca](https://en.wikipedia.org/wiki/Docendo_discimus)
32 |
33 | Literate Code Mapping is like teaching, mainly just to yourself. The act of drawing boxes with relationships and writing text explanations - to a decent level of literacy and professionalism *will* lead you to understand the code.
34 |
35 | Similarly, if you are not dealing with code but dealing with another domain - the same principle applies. Writing a high quality article for oneself is like a literate code map, it clarifies and solves. Try it: When taking notes whilst learning a new area - instead of scrappy notes and jumping from thought to thought, try consolidating your notes into a coherent, literate blog post that flow logically. In the end you'll have an artifact or even article that you can possibly share. More importantly, you will have understood the problem domain, and by re-reading your literate artifact, you will be able to rapidly refresh your memory at any time.
36 |
37 | If the domain is not diagram worthy, bullet points and outlines are enough. Some domains don't even need any structure like bullet points and plain text is enough - it's a continuum of tools we employ when being literate.
38 |
39 | The important thing is to be `literate`, which is the step by step thinking and exposition of a problem space to a quality level, which solves and explains the problem, for yourself and others.
40 |
41 | So, when analysing a domain or code-base, don't just rely on scrappy notes and jumping from thought to thought (in the case of code, jumping from file to file, trying to keep things in your head). That won't guarantee a solution. Be literate!
42 |
43 | ## Maximize data density
44 |
45 | As [Tuft](https://www.google.com/search?sxsrf=ACYBGNS1EpNz4CfrqW-z9eFY1ZGPhFiGFQ%3A1574306638649&ei=TgPWXbChJ--CrtoPldyooAE&q=tufte+principles&oq=tufte+principles&gs_l=psy-ab.3..35i39l2j0l3.18998.18998..20000...0.4..0.160.160.0j1......0....1..gws-wiz.......0i71.p3-NlWLJeD4&ved=0ahUKEwiwgNufrfrlAhVvgUsFHRUuChQQ4dUDCAs&uact=5)
46 | says: *"Visual representations of data must tell the truth... Above all else show data... Maximize data density"*.
47 | For programmers, data means source code including variables, data structures, sample values and payloads.
48 |
49 | The traditional UML class
50 |
51 | 
52 |
53 | becomes data rich and full of useful detail
54 |
55 | 
56 |
57 | A diagram need only list the code fragments that are required to tell a particular use case **story**.
58 |
59 | ## Numbered steps
60 |
61 | To avoid being lost in abstraction, Literate Code Maps rely on textual narrative and story telling,
62 | as well as numbered steps for the reader to follow.
63 | A diagram should have a starting point and a series of steps to follow, to tell a use case story:
64 |
65 | 
66 |
67 | Notice the box "H" which represents a HTML file - you see, boxes can represent any Namespace or Component - not just Classes, as we will see below.
68 |
69 | ## Cross References
70 |
71 | Use of cross reference numbers in the diagram handle the multi-dimensional relationships involved in thinking about and explaining software, and its cross cutting concerns.
72 |
73 | Cross references are red numbers e.g. `22` or `23` with destinations as e.g. `#22`.
74 |
75 | Lines between boxes are reserved for function calls.
76 |
77 | # Boxes represent any namespace
78 |
79 | In Literate Code Maps diagrams, boxes can represent any Namespace/Component/File/Thing - not just Classes.
80 | Even files can be represented as boxes in the diagram. Code Map diagrams boxes can thus represent:
81 |
82 | * classes
83 | * packages
84 | * functions
85 | * namespaces
86 | * files of any type e.g. HTML
87 | * module files of Python/C/Go/etc
88 | * sub-systems
89 | * any architectural or deployment grouping
90 | * etc.
91 |
92 | Code Map diagrams boxes are not tied to
93 | Object Oriented paradigms, and are thus more universal and useful.
94 |
95 | Instead of using square boxes, you might want to use different shapes e.g. https://blog.anoff.io/puml-cheatsheet.pdf shows all the component types you can use.
96 |
97 | It is recommended that boxes have a "stereotype" indicating what kind of box it is. For example for a Python module is stamped with an "M" which stands for module. To be explicit and less mysterious, we can also spell out the word "MODULE" and the path to the file in the diagram box. For HTML files the icon stereotype should be "H" with the word "HTML FILE" and the path to the file etc.
98 |
99 | ## HTML files as Boxes
100 |
101 | HTML files with fragments of HTML markup can be represented - great for showing how code interacts with HTML templating.
102 |
103 | 
104 |
105 | Javascript code fragments residing in the HTML file
106 | can be represented - see above diagram.
107 |
108 | ## Files of functions as Boxes (no classes)
109 |
110 | Files containing *just* functions and variables (no classes) can be represented as boxes in a way that makes them "look like" classes. For example, the Python file "utils.py"
111 |
112 | ```python
113 | x = 1
114 | y = 2
115 | def fred():
116 | pass
117 | ```
118 |
119 | turns into
120 |
121 | 
122 |
123 | which looks like a class, even though there is not a class in sight!
124 |
125 | Thus, Python programmers with modules (files) containing
126 | only variables and functions will be able to visualise their
127 | codebase. The online diagramming tool [GitUML](https://www.gituml.com) already supports reverse engineering Python modules into boxes in this way.
128 | This representational idea is also a boon for Javascript programmers who may have lots of variables and functions, and no classes. Together with the ability to visualise HTML files as boxes, web developers now have the ability to model aspects of their projects. Languages that may have files containing only functions include Python, Javascript, Kotlin, Delphi/Object Pascal, Go, C and many others. Regardless of the language and box type, ideally, the traditional data / behaviour separation in boxes should be followed.
129 |
130 | # Examples
131 |
132 | Here are some more examples of literate code maps.
133 |
134 |
136 |
137 | 
138 |
139 | ## More Complex Example
140 |
141 | 
142 |
143 |
144 | ## Event Flow (Literate Code Map Diagram)
145 |
146 | Here is an example of a Code Map of the event flow of a small application (my [TodoMVC-OO](https://github.com/abulka/todomvc-oo) implementation in Javascript using traditional OO and Controllers instead of fancy Javascript frameworks). Events are reified as coloured objects, each different event gets a different colour.
147 |
148 | > Note: The eventing pattern depicted here is [Publisher-Subscriber](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) where real event objects are 'broadcast' into the ether/event bus/system/whatever - allowing any code in the system to subscribe and respond - the point is, the code emitting the event does not have references to receiver object/methods. This eventing approach is more flexible and powerful than the [Observer](https://en.wikipedia.org/wiki/Observer_pattern) pattern since the Observer pattern requires observers to know about and subscribe to Subject objects, which is not always possible or convenient. More dicussion on the differences can be found [in this article](https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c) and on [Stackoverflow](https://stackoverflow.com/questions/6439512/difference-between-observer-pattern-and-event-driven-approach).
149 |
150 | >I used to be a fan of the traditional Observer pattern but in my later years find the Publisher-Subscriber pattern to be simpler and more powerful - plus Publisher-Subscriber is built into Javascript you simply `document.addEventListener("hello", (event) => { ... })` to listen and `document.dispatchEvent(new CustomEvent(event_name, { detail: {from: from, data: data } }))` to notify all.
151 |
152 | Notice in the following code map diagram the:
153 | - use of **colour** on the dotted lines *(representing events being triggered and received)*
154 | - use of corresponding **colour** on the event
155 | - use of corresponding **colour** of the code fragments
156 |
157 | 
158 | *(click on diagram for more detail and the ability to zoom)*
159 |
160 | # Building your own Literate Code Maps
161 |
162 | By building a Literate Code Map of a particular use case story in your code base, you *will* end up understanding the source code - and be able to effectively fix a bug or add a feature. As a bonus, you can refer to your code map in the future, and share it with colleagues.
163 |
164 | >Think of building a Literate Code Map as the process of "taking notes" as you study code - something that most programmers aleady do. The benefit of a code map is that the diagram auto-lays out as it grows and changes, always looking good. Plus by following the 5 laws of literate code mapping, you have a simple methodology to follow rather than unstructured and undisciplined personal notes that cannot be shared and will likely end up in the bin.
165 |
166 | It is recommended to use [PlantUML](https://plantuml.com/) markup to generate your Literate Code Map diagrams. [GitUML](https://www.gituml.com) supports building Literate Code Map diagrams online with a built in PlantUML editor plus useful PlantUML snippets that support Literate Code Mapping e.g. adding a "code compartment" or cross reference.
167 |
168 | To create code compartment in boxes/classes, use the following markdown sytax e.g.:
169 |
170 | .. def myfunction(param1, param2): ..
171 |
172 | For each box, first list attributes and methods
173 | in the traditional UML way, with a dividing line between them - let's
174 | call this the summary view.
175 | Then append extra compartments within the box for each method
176 | we are interested in expanding upon with code detail and text narrative.
177 | Any methods which are expanded, should be bolded in the UML summary view
178 | of methods, so that the reader knows there is more detail below.
179 |
180 | > When using PlantUML to build Literate Code Maps, it is useful to know that you can define a class multiple times and PlantUML will combine all the definitions into the one box. In this way you can incrementally build up the diagram. You could create one piece of PlantUML to define the summary view, then another piece of PlantUML to create the additional code detail compartments.
181 |
182 | class Shape {
183 | canvas
184 | parent
185 | --
186 | SetCanvas()
187 | GetParent()
188 | SetBrush()
189 | }
190 |
191 | class Shape {
192 | .. SetCanvas() ..
193 | Narrative rich text comments and code about this method here.
194 |
195 | .. GetParent() ..
196 | Narrative rich text comments and code about this method here.
197 | $code ...
198 | }
199 |
200 | ## Source Code fragments
201 | To include source code fragments inside the "code compartments" of boxes, define this handy macro at the top of your PlantUML e.g.:
202 |
203 | !$code = ""
204 |
205 | then simply add the word `code` before each line of your code fragment. Use spaces to indent, or `\t`.
206 |
207 | $code for i in range(100):
208 | $code print(i)
209 |
210 | >__Tip:__ By using [GitUML](https://www.gituml.com) to build code maps, you can use simply surround source code fragments with the usual ``` syntax - which is much easier than prepending `$code` before each source code line.
211 |
212 | View the [examples directory](https://github.com/abulka/lcodemaps/tree/master/plantuml) for the full source code to the code maps used in this article.
213 |
214 | ## Tools to build code maps
215 | [GitUML](https://www.gituml.com) supports building UML and Literate Code Map diagrams online, using a combination of source code reverse engineering and PlantUML markup.
216 |
217 | [](https://www.youtube.com/watch?v=ZnVMOhaIIM8 "Quick Start - Creating a diagram and adding a code map compartment")
218 | *2 minute video tutorial*
219 |
220 | ### Zoom
221 |
222 | Literate Code Maps are ideally generated as `.svg` files so that users can zoom in to view more detail and there is never any loss of important detail. All the diagrams in this article are SVG and can be clicked on and zoomed into.
223 |
224 | ### Diagram Size
225 |
226 | The public PlantUML server used to render some of these code maps has a limit on the size of the diagrams it produces. You can easily set up your own PlantUML server locally which not only is faster, but can generate much larger diagrams before clipping them. See the [PlantUML Server Documentation](https://plantuml.com/server). See also the helpfile in [Pynsource](www.pynsource.com) (Python UML tool for Mac, Windows, Linux) as it contains more specific PlantUML server local install instructions.
227 |
228 | # History - Why Code Maps?
229 |
230 | Whenever I have encountered a huge codebase, or an old project I wrote myself, or just a complex code area - I typically trace out and make notes as I read the code. How many programmers do something similar? Here is an example of a hand-crafted literate code map:
231 |
232 | ## Evolution - stage 1
233 | 
234 |
235 | Over the years, this became a useful and effective habit: when stuck, take a breath, respect the difficulty of the situation and - build a literate code map. Eventually I started copying and pasting code fragment screenshots into a paint tool - why re-write when you can copy and paste! I connected the boxes with lines and added use usual narrative text comments. This was a *little* more professional, but gee - I wish I had auto-layout so that I could squeeze and rearrange the diagram when I discovered new things. Here is an example of an old hand built 'digital' literate code map diagram:
236 |
237 | ## Evolution - stage 2
238 | 
239 |
240 | Finally I moved on to using PlantUML markup code - allowing the diagrams and notes to be automatically laid out, be pretty to look at and maintainable.
241 |
242 | ## Evolution - stage 3
243 | 
244 |
245 | The above diagram was created in [GitUML](https://www.gituml.com) which supports building Literate Code Map diagrams online with a built in PlantUML editor plus useful PlantUML snippets that support Literate Code Mapping e.g. adding a "code compartment" or cross reference.
246 |
247 | This is still "state of the art" in terms of convenience and automatic layout etc, despite my thoughts below on the evolution of Literate Code Mapping stage 4. But if you want a really handcrafted, super-precise diagram with close links to your source code and use the vscode editor, read on!
248 |
249 | ## Evolution - stage 4 (2021)
250 |
251 | In June 2021 I discovered that the free diagramming tool draw.io had an [extension for Vscode](https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio&ssr=false#overview), which allowed you to draw diagrams without leaving vscode. So for fun I manually built a literate code map of some code I was working on - all handcrafted with copy and paste etc. By breaking up the diagram into smaller pieces (viz. ensure a function call source line or a method definition source line is its own text object in draw.io), I was able to get arrow 'calls' from and to the actual line of source code that I wanted - very precise.
252 |
253 | 
254 | *Demonstrates a literate code map built in draw.io*
255 |
256 | In this diagram source code areas (a key feature of literate code mapping) are attempted as both a screen shot (faster to make) and also as copy pasted text (had to correct indenting after paste).
257 |
258 | Draw.io has
259 | - lots of formatting (text, colour etc) choices for my diagramming.
260 | - the ability to collapse and expand diagram areas - very handy when building large diagrams - there is a layout feature too.
261 | - custom template shapes - I'm thinking about building a set to help hand craft literate code maps using draw.io.
262 | - an ability to liveshare to present or edit diagrams collaboratively
263 | - the ability to paste screenshots into a diagram - I used this to screen shot some code rather futzing with copy paste of text and correcting and indenting the resulting diagram text box - it was faster.
264 | - the ability to link a screenshot or a text box node of e.g. a react component "MyComponent" with its source by naming the node "#MyComponent"?
265 |
266 | This last feature (the 'code linking' feature of draw.io) is possibly the coolest - whereby adding `#symbolname` text to any diagram object auto navigates to the source code of that symbol when you double clicked it (make sure drawio code linking is toggled on in the bottom status bar). This means that I can jump from the diagram to the source code with a double click - very powerful.
267 |
268 | 
269 | *Demonstrates a literate code map built in draw.io, double clicking on diagram areas to jump to associated source code & collapsing diagram areas.*
270 |
271 | - View raw gif [literate-drawio-vscode-01](https://github.com/abulka/lcodemaps/blob/master/images/literate-drawio-vscode-01.gif) gif.
272 | - Download the above [renaming.drawio](https://github.com/abulka/lcodemaps/blob/master/images/renaming.drawio) diagram file.
273 |
274 |
275 | ### Further thoughts on draw.io
276 | Whilst this 'stage 4' evolution of Literate Code Mapping is not as automated and rapid as that supported by [GitUML](https://www.gituml.com), it does show how a rich diagramming tool could take literate code mapping to another level - esp. with with source code linking and collaboration features.
277 |
278 | The draw.io approach to building literate code maps is currently relatively slow and tedious, very hand crafted, very 'literate' in the sense that you have lots more control to be as non-UML as you like. To mitigate this with some automation, I'm thinking that a Literate Code Mapping Vscode extension could perhaps be built to communicate with the draw.io diagram to automatically parse code, build UML style objects and embed literate code mapping areas automatically, from selected code fragments.
279 |
280 |
281 | # Tufte
282 |
283 | Whilst I knew my literate code maps worked (for me, personally) - I didn't have any research or scientific backing for them.
284 |
285 | Then I thought of Edward Tuft's visualisation work, which I have been a fan of for a long time. Sure enough, his ideas on density, detail, rich formatting, use of icons and small graphics at any place where you would put text - are all consistent with literate code maps. Especially the idea of combining detail and abstraction in the same diagram - the boxes are the abstraction and the code is the detail.
286 |
287 | I hope to tie more of Tufte's insights into the Literate Code Map methodology, as well as draw from the vast field of [Information Visualization](https://en.wikipedia.org/wiki/Information_visualization).
288 |
289 | > Wikipedia says “Information visualization presumes that "visual representations and interaction techniques take advantage of the human eye’s broad bandwidth pathway into the mind to allow users to see, explore, and understand large amounts of information at once. Information visualization focused on the creation of approaches for conveying abstract information in intuitive ways.
290 |
291 | I also like many of the ideas of [C4 architecture notation](https://c4model.com) e.g. each line being labelled and having a direction. C4 also has some good criticisms of UML in the main C4 video, which I encourage people to watch.
292 |
293 | # UML
294 |
295 | Literate Code Maps are not UML.
296 |
297 | Code Maps are more detailed and can actually be used to debug code and add features, because they contain code fragments which are relevant to day to day programmers. They contain narrative, story telling text - which leverages how we learn. They also take advantage of the human eye’s broad bandwidth pathway to take in visual information.
298 |
299 | UML *is* useful when judiciously used, but most UML diagrams tend to be too abstract to actually be helpful to a programmer. As I write in [my blog](https://www.andypatterns.com/),
300 |
301 | > UML (Unified Modelling Language) has fallen out of favour in the last decade and now tends to only get used in the most basic of ways. Sketches on whiteboards to commuicate class relationships or code execution sequences. Or simple diagrams in documentation and designs. Nobody uses the complex notations of UML 2, because digramming cannot keep up with the myriad programming techniques and paradigms of 2018 - code is simply not reducible to visual information.
302 |
303 | I think that there are a limited numbers of cases where UML diagrams might be helpful:
304 | - whiteboard communication
305 | - database modelling
306 | - reverse engineering existing projects to understand them (see [GitUML](https://gituml.com))
307 | - big picture architecture diagrams (also see [C4 architecture notation](https://c4model.com))
308 | - class diagrams of complex class relationships
309 | - representing design patterns
310 | - sequence diagrams of certain code behaviours
311 | - state diagrams are also sometimes useful
312 |
313 | UML usually lacks normal human, tutorial-like, step by step narrative textual storytelling and code level detail. Staring at at a UML diagram typically leaves you wanting much more detailed information. Staring at source code typically leaves you wanting a diagram of relationships and context. Literate Code Maps are an attempt to solve this problem.
314 |
315 | # Contributing
316 |
317 | If you wish to contribute to this diagramming specification I am open to pull requests via the project's dedicated [Github Repository](https://github.com/abulka/lcodemaps).
318 |
319 |
320 | Let's make Literate Code Mapping a practical, useful visualisation technology that can, on ocassion, help software development - without the old UML preconceptions and baggage.
321 |
322 | # Resources
323 |
324 | - Literate Code Maps [Documentation Home Page](https://abulka.github.io/lcodemaps/).
325 | - Literate Code Maps [Github Repository](https://github.com/abulka/lcodemaps)
326 |
--------------------------------------------------------------------------------
/images/example-01.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/example-02.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/handcrafted-code-map-andy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abulka/lcodemaps/d40f7437cbe5a3484fb2136118f2c32a87aa7ceb/images/handcrafted-code-map-andy.png
--------------------------------------------------------------------------------
/images/handcrafted-screenshot-based-code-map-andy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abulka/lcodemaps/d40f7437cbe5a3484fb2136118f2c32a87aa7ceb/images/handcrafted-screenshot-based-code-map-andy.jpg
--------------------------------------------------------------------------------
/images/literate-drawio-vscode-01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abulka/lcodemaps/d40f7437cbe5a3484fb2136118f2c32a87aa7ceb/images/literate-drawio-vscode-01.gif
--------------------------------------------------------------------------------
/images/literate-drawio-vscode-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abulka/lcodemaps/d40f7437cbe5a3484fb2136118f2c32a87aa7ceb/images/literate-drawio-vscode-01.png
--------------------------------------------------------------------------------
/images/renaming.drawio:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/plantuml/basic-codemap.puml:
--------------------------------------------------------------------------------
1 | @startuml Basic idea of a literate code map
2 |
3 | !$code = ""
4 | !$codeb = ""
5 | !$codeg = ""
6 | !$codeb = ""
7 | !$codep = ""
8 |
9 | class Payroll {
10 | last_run: date
11 | employees[]: list #22 $codeg this can be implemented as attr or DB call
12 | ----
13 | pay()
14 | count()
15 | auth_to_bank()
16 | .. def pay(): ..
17 | We loop through all employees and only pay them
18 | if they can be located. 😄
19 |
20 | $codeb for employee in employees:
21 | $codeb found = employee.locate()
22 | $codeb ...
23 | $codeb ...
24 | $codeb if found:
25 | $codeb bank.send_money(
26 | $codeb \t employee.bank_ac_number,
27 | $codeb \t employee.salary)
28 | $codeb ...
29 |
30 | .. def count(): ..
31 | We simply return the length of the employees
32 | attribute which is a list.
33 |
34 | $codeb return employee.length()see 22.
35 |
36 | However when this is turned into a database facing method in version two
37 | we will need to change the implementation
38 |
39 |
40 | | Version | Implementation |\n| V1 | List |\n| V2 | Django ORM DB query |
41 |
42 | e.g. something like
43 |
44 | $codeb return employee.Objects.all().count()
45 | }
46 |
47 |
48 | @enduml
49 |
--------------------------------------------------------------------------------
/plantuml/basic-uml.puml:
--------------------------------------------------------------------------------
1 | @startuml Basic UML class diagram
2 |
3 | class Payroll {
4 | employees[]
5 | pay()
6 | count()
7 | }
8 |
9 | @enduml
--------------------------------------------------------------------------------
/plantuml/example-01.puml:
--------------------------------------------------------------------------------
1 | @startuml More complete example of a Literate Code Map - 01
2 |
3 | !$code = ""
4 | !$codeb = ""
5 | !$codeg = ""
6 | !$codeb = ""
7 | !$codep = ""
8 |
9 | header
10 | Prototype of "Literate Code Maps"
11 | (c) Andy Bulka 2019
12 |
13 | endheader
14 |
15 | class View {
16 | onKeyUp()
17 | onClick()
18 | ---
19 | .. def onClick() ..
20 |
21 | Responsible for handling the clicl event.
22 | Calls GetShapeList() on the Diagram to get all the shapes, then iterates
23 | through them, checking each shape's parent.
24 |
25 | $code ..
26 | $code for shape in self.GetDiagram().GetShapeList(): 2
27 | $code if shape.GetParent() == None: 3
28 | $code ..
29 |
30 | .. def onKeyUp(self, event) ..
31 |
32 | Handles the ESC key being hit and switches the canvas
33 | $code ..
34 | $code shape.SetCanvas(None) 4
35 | $code ..
36 | }
37 | class Shape {
38 | canvas
39 | parent
40 | --
41 | SetCanvas()
42 | GetParent()
43 | SetBrush()
44 | }
45 | class Diagram <> {
46 | shapes
47 | ---
48 | GetShapeList()
49 | Render()
50 | Clear()
51 | Scan()
52 | .. GetShapeList() ..
53 | $code ...
54 | $code result = []
55 | $code for each shape in shapes:
56 | \tvarious filtering conditions, if succesful,
57 | \tshape gets appended to the result
58 | $code return result
59 |
60 | .. Render() ..
61 | Create fresh visualisation
62 |
63 | $code for node in self.displaymodel.graph.nodes:
64 | $code assert not node.shape
65 | $code if isinstance(node, CommentNode) or hasattr(node, "comment"):
66 | $code shape = self.createCommentShape(node) 22
67 | $code else:
68 | $code shape = self.CreateUmlShape(node)
69 | }
70 |
71 | class Shape {
72 | .. SetCanvas(canvas) ..
73 | $code ...
74 | $code self.canvas = canvas 4
75 | $code ...
76 | .. GetParent() ..
77 | Simply a reference to the .parent property,
78 | which is None if there is no parent.
79 | $code ...
80 | $code return self.parent
81 | }
82 |
83 | class Scenario1 < when user clicks on button ><< (S,#FF7700) start here >>
84 |
85 | Scenario1 ..> View : 1. onClick()
86 | View ..> Diagram : 2. GetShapeList()\n -> List
87 | View ..> Shape : 3. GetParent()\n -> Shape
88 | View ..> Shape : 4. SetCanvas()
89 |
90 |
91 |
92 | note as N2
93 | The creation of a comment shape
94 | if a little different 22
95 | end note
96 | N2 . View
97 | N2 .[hidden] View
98 |
99 | note "The list of shapes is kept in the diagram, which the view uses" as N3
100 | N3 .. View
101 | N3 .. Diagram
102 |
103 | center footer
104 |
105 | A "Literate Code Map" diagram
106 | combines class and sequence diagrams into one.
107 | Plus adds code fragments, rich narrative text and numbered references.
108 | end footer
109 |
110 | @enduml
111 |
--------------------------------------------------------------------------------
/plantuml/example-02.puml:
--------------------------------------------------------------------------------
1 | @startuml More complete example of a Literate Code Map - 02
2 |
3 | !$code = ""
4 | !$codeb = ""
5 | !$codeg = ""
6 | !$codeb = ""
7 | !$codep = ""
8 |
9 | header
10 | File Upload Story - Literate Code Map
11 | (c) Andy Bulka 2019
12 | endheader
13 |
14 | class urls < START HERE: when user clicks on file upload link ><<(M,#FF7700) singlepage/urls.py>>{
15 | .. urlpatterns ..
16 | /fileupload -> $codeb views.fileupload 1 * main user start point
17 |
18 | /upload_file -> $codeb views.upload_file
19 | /file_upload_uml// -> $codeb views.file_upload_uml
20 | }
21 |
22 | class views <<(M,#FF7700) singlepage.views.py>> {
23 | .. def fileupload(request): ..
24 | $codeb 1.
25 | $codeb return render(request,
26 | $codeb\t"fileupload.html", {"object_list": None}) $codeb 2.
27 |
28 | .. def upload_file(request, uid=None): ..
29 | $codeb 3.
30 | Calculates an "event" based on the user name and date, and stores all
31 | uploaded files in a directory UPLOAD_DIR/event.
32 |
33 | $codeb form = FileUploadForm(request.POST, request.FILES or None)
34 | $codeb file = request.FILES['file']
35 | $codeb event = calc_upload_eventdir(request.user, datetime.datetime.now())
36 | $codeb dir = os.path.join(UPLOAD_DIR, event)
37 | $codeb path = os.path.join(dir, file.name)
38 | $codeb handle_uploaded_file(file, path) $codeb A1.
39 |
40 | $codeb return HttpResponse(json.dumps(data), content_type="application/json")
41 | Typical AJAX HttpResponse is
42 | $codeg : {'status': 'success',
43 | $codeg 'file': 'display_model.py',
44 | $codeg 'event': 'admin-1-2019-04-17-12:12:47'}
45 |
46 | .. def handle_uploaded_file(file, path=None): ..
47 | $codeb A1.
48 | This should be changed to using memcache rather than the local file system!
49 | $codeb path = os.path.join('uploaded', file.name) # work out dir
50 | $codeb os.makedirs(os.path.dirname(path)) # and create dir
51 | $codeb with open(path, 'wb+') as destination: ... destination.write(chunk) # writes out file
52 |
53 | .. def file_upload_uml(request, event): ..
54 | $codeb 4.
55 | $codeb 6.
56 | Called when all files have been successfully uploaded.
57 | "event" gives us a way to refer to those files.
58 | Combines custom plantumltext (which initially will be blank) into a UML diagram based on paths
59 |
60 | $codeb image_url, generated_plant_uml_text = uploaded_local_paths_to_uml_url(
61 | $codeb paths, custom_plant_uml_text, ..., options_uml
62 | $codeb )
63 |
64 | then where do we go?
65 | well, we render the "fileupload_uml.html" template
66 |
67 | $codeb form = MyFileUploadForm(initial={"custom_plant_uml_text": ""})
68 |
69 | which is
70 | $codeb class MyFileUploadForm(forms.Form):
71 | $codeb custom_plant_uml_text = forms.CharField(
72 | $codeb label="Additional custom plantuml text", required=False, widget=forms.Textarea
73 | $codeb )
74 | Note that it is not inheriting from forms.ModelForm
75 |
76 | $codeb return render(
77 | $codeb request,
78 | $codeb "fileupload_uml.html", $codeb 5.
79 | $codeb {
80 | $codeb "python_text": python_text,
81 | $codeb # "show_python_text": True,
82 | $codeb "generated_plant_uml_text": generated_plant_uml_text,
83 | $codeb "custom_plant_uml_text": None,
84 | $codeb "image_url": image_url,
85 | $codeb "form": form,
86 | $codeb "event": event,
87 | $codeb "paths_ro": paths_ro,
88 | $codeb },
89 | $codeb
90 | }
91 |
92 | class fileupload <<(T,#FF7700) singlepage/templates/fileupload.html>> {
93 | Change /upload-target to your upload address, in this case it is "upload_file"
94 | for each file
95 |
96 | $codeb 3.
97 | $codeb
100 | .. javascript ..
101 | once all files have been uploaded
102 | $codeb function submit_upload_uml_event()
103 | $codeb event = last_upload_event
104 | $codeb window.location.href = 'file_upload_uml/[object Event]' $codeb 4.
105 | }
106 |
107 | class fileupload_uml <<(T,#FF7700) singlepage/templates/fileupload_uml.html>> {
108 | Actually displays the UML diagram. The only thing we upload
109 | via the form is the custom plantuml. The "event" parameter of the url
110 | lets us find the source files etc.
111 | $codeb width="200" height="100"> #33
26 | $codeb
27 |
28 | .. function submit_upload_uml_event() ..
29 | once all files have been uploaded we redirect
30 | to the $codeb file_upload_uml/ endpoint
31 |
32 | $codeb ...
33 | $codeb function submit_upload_uml_event()
34 | $codeb event = last_upload_event
35 | $codeb window.location.href = 'file_upload_uml/${event}'
36 |
37 | .. function render(): ..
38 | This uses the canvas see33
39 | to draw the shape
40 | $codeb ...
41 | $codeb var c = document.getElementById("myCanvas"); $codeg non jquery ref to canvas $normal see 33
42 | $codeb var ctx = c.getContext("2d");
43 | $codeb ctx.moveTo(0, 0);
44 | $codeb ctx.lineTo(200, 100);
45 | $codeb ctx.stroke();
46 | $codeb ...
47 |
48 | See [[https://www.w3schools.com/html/html5_canvas.asp]]
49 | for more information on canvas drawing.
50 | }
51 |
52 | @enduml
--------------------------------------------------------------------------------
/plantuml/numbered-steps.puml:
--------------------------------------------------------------------------------
1 | @startuml numbered steps
2 |
3 | !$code = ""
4 | !$codeb = ""
5 | !$codeg = ""
6 | !$codeb = ""
7 | !$codep = ""
8 |
9 | class Scenario1 < when user clicks on button ><< (S,#FF7700) start here >>
10 |
11 | class View {
12 | onClick()
13 | }
14 |
15 | class CoordinateManager {
16 | getEventLocation(point)
17 | }
18 |
19 | class Shape {
20 | render()
21 | .. def render(): ..
22 | This uses the canvas to draw the shape
23 | $codeb ...
24 | $codeb var c = document.getElementById("myCanvas");
25 | $codeb ...
26 | }
27 |
28 | class index <<(H,#FF7700) HTML FILE templates/index.html>> {
29 | This is the HTML fragment containing
30 | the canvas DOM element
31 |
32 | $codeb width="200" height="100">
33 | $codeb
34 | }
35 |
36 | Scenario1 ..> View : 1. user clicks mouse on canvas\nonClick()
37 | View ..> CoordinateManager : call from onClick()\n2. calculate what is being clicked on\ngetEventLocation(point)
38 | View ..> Shape : call from onClick()\n3. draw the shape\nrender()
39 | Shape ..> index : from render()\n4. refer to the canvas\nid="myCanvas"
40 |
41 | @enduml
--------------------------------------------------------------------------------
/plantuml/python-module.puml:
--------------------------------------------------------------------------------
1 | @startuml Example of Python module as pseudo class
2 |
3 | class utils <<(M,#FF7700) MODULE utils.py>> {
4 | x
5 | y
6 | ---
7 | fred()
8 | }
9 |
10 | @enduml
11 |
--------------------------------------------------------------------------------