Skip to content

Commit f9d10d5

Browse files
committed
Add first parts of reworked flow-dev guide
1 parent ff9e595 commit f9d10d5

15 files changed

Lines changed: 420 additions & 93 deletions

_includes/developing-flows-toc.html

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<ul class="toc">
2+
<li class="toc-expander"><div>V</div></li>
3+
<li class="tocheader">
4+
<ul>
5+
<li class="toctitle active"><a href="/docs/developing-flows/">Developing Flows</a></li>
6+
<li {% if page.url == "/docs/developing-flows/flow-structure" %}class="active"{% endif %}><a href="/docs/developing-flows/flow-structure">Flow structure</a></li>
7+
<li {% if page.url == "/docs/developing-flows/message-design" %}class="active"{% endif %}><a href="/docs/developing-flows/message-design">Message design</a></li>
8+
<li {% if page.url == "/docs/developing-flows/error-handling" %}class="active"{% endif %}><a href="/docs/developing-flows/error-handling">Error handling</a></li>
9+
<li {% if page.url == "/docs/developing-flows/documenting-flows" %}class="active"{% endif %}><a href="/docs/developing-flows/documenting-flows">Documenting Flows</a></li>
10+
</ul>
11+
<hr>
12+
<i>
13+
<ul>
14+
<li {% if page.url == "/docs/developing-flows/designing" %}class="active"{% endif %}><a href="/docs/developing-flows/designing">Designing</a></li>
15+
<li {% if page.url == "/docs/developing-flows/implementation" %}class="active"{% endif %}><a href="/docs/developing-flows/implementation">Implementation</a></li>
16+
<li {% if page.url == "/docs/developing-flows/readability" %}class="active"{% endif %}><a href="/docs/developing-flows/readability">Readability</a></li>
17+
<li {% if page.url == "/docs/developing-flows/multiple-developers" %}class="active"{% endif %}><a href="/docs/developing-flows/multiple-developers">Project</a></li>
18+
<li {% if page.url == "/docs/developing-flows/non-functional" %}class="active"{% endif %}><a href="/docs/developing-flows/non-functional">Non-functional requirements</a></li>
19+
</ul>
20+
</i>
21+
</li>
22+
</ul>
23+
<script>
24+
$(function() {
25+
var pageToc = $("<ul></ul>").appendTo(".toc li.active:not(.toctitle)");
26+
$(".docs-content h3,.docs-content h4").each(function() {
27+
$('<li id="toc-item-'+$(this).attr('id')+'"><a style="font-size: 0.9em; padding-left: 50px;" href="#'+$(this).attr('id')+'">'+$(this).text()+'</a></li>').appendTo(pageToc)
28+
})
29+
})
30+
</script>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{% assign parent_url = '/docs/developing-flows/' %}
2+
{% assign parent_slug = 'developing flows' %}
3+
{% include docs-content.html %}

docs/developing-flows/designing.md

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
---
2-
layout: docs
3-
toc: developing-flows-toc.html
4-
title: Designing flow
2+
layout: docs-developing-flows
3+
toc: toc-developing-flows.html
4+
title: Designing flows
55
---
66

7+
***This content is under review and may not form part of the final flow developer guide***
8+
79
### Development steps
8-
10+
911
If a project needs complicated logic, it is better to design flow before starting development. After that, you create flows based on the flow design. In this subsection, we show an overview of whole recommended steps of design and development.
10-
12+
1113
* Design
1214
- Flow structure
1315
- Message
1416
* Implementation
15-
17+
1618
### Designing flow structure
1719

1820
{% comment %}
@@ -39,7 +41,7 @@ If you are developing with multiple developers, it is better to design flows for
3941

4042
#### Subflow
4143

42-
If the same processing needs to be repeated, creating the same nodes sequence several times will not only reduce readability, but will also require changing all applicable nodes, even when they need to be modified.
44+
If the same processing needs to be repeated, creating the same nodes sequence several times will not only reduce readability, but will also require changing all applicable nodes, even when they need to be modified.
4345
You can solve these problems by turning nodes into subflow, and changing icons.
4446

4547
<div style="text-align: center">
@@ -49,8 +51,8 @@ You can solve these problems by turning nodes into subflow, and changing icons.
4951
For example, if the process of sending e-mail is written as a sub-flow, it can be reused to create a flow in which other processes send e-mail.
5052

5153
### Designing messages
52-
53-
There are risks that multiple nodes have dependencies by messages passing through nodes. For other developers to reuse flows, it is important to design messages so that dependencies get to be relaxed.
54+
55+
There are risks that multiple nodes have dependencies by messages passing through nodes. For other developers to reuse flows, it is important to design messages so that dependencies get to be relaxed.
5456

5557
{% comment %}
5658
This chapter proposes a guide about designing message.
@@ -84,7 +86,7 @@ You better to design the messages before implementing a flow.
8486

8587
{% comment %}
8688
*`msg` is a JavaScript object that contains a key-value structure like JSON. While a `msg` transits across multiple nodes, the nodes use some keys and values of the `msg`. If two or more nodes of them use the same key for different their own purposes, preparing `msg` for input of the nodes is so difficult.*
87-
89+
8890
*Therefore, strategy of key-value structure are needed and this subsection describes it as followings,*
8991
{% endcomment %}
9092

@@ -128,9 +130,9 @@ This verification process also expresses the boundaries of dependencies between
128130
{% endcomment %}
129131

130132
#### Keeping properties
131-
133+
132134
In the case of using `Function` node, you can prepare output messages by creating new `msg` objects. However, the output messages may not have some properties that the input message has. This means that properties that should be kept in your flow has lost. Since this can be a cause of serious bugs, preparing output messages based on an input message is better, instead of creating new `msg`.
133-
135+
134136
#### Add tag into `msg` to distinguish a node that sent the `msg`
135137

136138
{% comment %}
@@ -146,7 +148,7 @@ Specifically, you assign a tag that identifies the execution path as a message p
146148
</div>
147149

148150
#### Using persistent storage outside of Node-RED
149-
151+
150152
If you handle the large amount of data, it is **not** recommended to set the data into `msg` since `msg` can exhaust available memory.
151153

152154
{% comment %}
@@ -173,7 +175,7 @@ You can also make the debugging process easier by adding error handling processi
173175

174176

175177
#### Processing messages in order of their arrival
176-
178+
177179
Since Node-RED (JavaScript) processes asynchronously, a node cannot assume that it executes process for arrival `msgs` by the order of arrival.
178180

179181
You should design the flow so that processing does not depend on the order in which messages arrive.
@@ -182,8 +184,8 @@ That is, your flow should produce the correct result even if messages arrive in
182184
If you want to design the flow depending on messages in order, you should use `Sort` node. You can check how to use `Sort` node at **Sequential guarantee** of [Non-functional requirements](non-functional).
183185

184186
{% comment %}
185-
If you want to assume processes by the order of arrival, try this code.
186-
187+
If you want to assume processes by the order of arrival, try this code.
188+
187189
```javascript
188190
// Accumulation of messages
189191
var msgs = context.get('messages') || [];
@@ -192,6 +194,6 @@ if(msgs.length === ...) {
192194
... // Process messages
193195
}
194196
context.set('messages', msgs);
195-
197+
196198
```
197199
{% endcomment %}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
---
2+
layout: docs-developing-flows
3+
toc: toc-developing-flows.html
4+
title: Documenting flows
5+
slug: documenting flows
6+
---
7+
8+
In any programming language, a vital part of creating easy-to-maintain code is to ensure it is also well documented.
9+
10+
Good documentation serves a number of purposes:
11+
12+
1. Whilst everything may seem obvious as you are building a flow, your future self will thank you for providing some description of the details when you come back to it later.
13+
2. If you are sharing a flow with others, it will help them understand what it is doing and how it works.
14+
3. If a flow provides an external API you will want to document how that API should be used - what properties or parameters are expected.
15+
4. When you write documentation, the act of writing out the behaviour could well help you identify parts that could be improved.
16+
17+
In a visual programming environment like Node-RED, the documentation can take a number of forms.
18+
19+
- The flows can be read in the workspace to see the logical flow of events. You should make sure the purpose of each node is easily identified and that they are well laid out to minimise how much wires cross each other.
20+
- Groups can be used to identify discrete sections of the flows.
21+
- Moving commonly used parts into subflows can help reduce the visual complexity of the flow.
22+
- More complete documentation can be added at the node, group or tab level
23+
24+
25+
### Laying out flows
26+
27+
The [flow structure](flow-structure) section of this guide looked at how to arrange the logical components of your flows. This section considers the visual appearance of the flow layout.
28+
29+
The goal is to make it easy to follow the flow without having to jump around the workspace or have to follow multiple wires that cross each other and appear tangled.
30+
31+
The approach that gives the greatest legibility is to keep each unit of processing on a single horizontal line wherever possible. The editor's default behaviour of snapping nodes to a grid on the tab helps keep them aligned.
32+
33+
<div class="figure">
34+
<img src="./images/node-arrangement-sample.png" alt="Placeholder caption"/>
35+
<p class="caption">Placeholder caption</p>
36+
</div>
37+
38+
If there is a node that has more than one output port, aligning the branched flow vertically makes it easy to compare and contrast the flows.
39+
40+
<div style="width: 600px" class="figure">
41+
<img src="images/placeholder.png" alt="Link nodes">
42+
<p class="caption">Placeholder for image: Cut above image in half - move Power Usage Calculation Service half here</p>
43+
</div>
44+
45+
When a flow gets too long, arranging some nodes vertically can be used to good effect. In the following figure, some of the nodes are arranged vertically to imply a relationship between them. It is easier to understand the nature of the overall flow if it is visually obvious what smaller sections it is comprised of and how they relate to each other.
46+
47+
<div class="figure">
48+
<img src="./images/node-vertical-arrangement.png" alt="Placeholder caption"/>
49+
<p class="caption">Placeholder caption</p>
50+
</div>
51+
52+
In some cases, these smaller sections may be candidates for moving to subflows that will reduce the visual complexity of the flow. That is particular true if that smaller section could be reused elsewhere in the flows.
53+
54+
### Naming nodes
55+
56+
Most nodes have a `name` property that can be used to customise the label they display in the workspace. This should be used to properly label the key points of a flow.
57+
58+
For example, if a Change node has a single rule that sets `msg.payload` to the current time, its default label will be `set msg.payload`. That helps somewhat, but it doesn't reveal the full purpose of the node. A name of `Get current time` would be much clearer.
59+
60+
There is a balance to be considered here. The longer the label, the more space it needs in the flow. The shorter the label, the less information it can share.
61+
62+
For some nodes, it might be appropriate to hide the label altogether to minimise the horizontal space it uses in the flow - giving more room to other nodes.
63+
64+
Along with the label, nodes can also have a custom icon. For example, if you have a number of MQTT In nodes for different types of device, customising the icon to match the type of device could be helpful. This should be used with care as the icon is one of the main ways of identifying the type of a particular node
65+
66+
Choosing good names for things applies just as much to the tabs and subflows used.
67+
68+
It also very important for Link nodes. Without a name set, you have to use the Link node's internal ID when creating links between different tabs. That makes it hard to identify the right target node and mistakes can happen. If you consider the Link nodes as providing APIs between the different tabs, then a good choice of naming scheme will be needed.
69+
70+
### Adding port labels
71+
72+
If a node has multiple outputs it can be hard to follow the logic if it is not clear on what condition a message may be sent from a particular output.
73+
74+
This is where adding port labels can help document the intended logic.
75+
76+
For example, the Switch node provides default labels for its outputs that are shown when the mouse hovers over them. They can help quickly identify the purpose of each branch in the flow.
77+
78+
Whilst the default labels may be sufficient in the context of the flow itself, it is also possible to custom labels to provide more detailed information.
79+
80+
<div style="width: 600px" class="figure">
81+
<img src="images/placeholder.png" alt="Link nodes">
82+
<p class="caption">Placeholder for image: Port labels</p>
83+
</div>
84+
85+
### Inline Comments
86+
87+
The Comment node can be used to add inline comments to the flow - both the node's label, but also its description that will show in the Information sidebar when selected.
88+
89+
By indenting the flows on the page, you can indicate an implied grouping of the different components.
90+
91+
<div style="width: 600px" class="figure">
92+
<img src="images/placeholder.png" alt="Link nodes">
93+
<p class="caption">Placeholder for image: Indenting with Comments</p>
94+
</div>
95+
96+
### Grouping nodes
97+
98+
A more explicit arrangement of the flows can be achieved by grouping related nodes together.
99+
100+
The background colour of each group can also be used to highlight different types of group.
101+
102+
<div style="width: 600px" class="figure">
103+
<img src="images/placeholder.png" alt="Link nodes">
104+
<p class="caption">Placeholder for image: Grouping nodes</p>
105+
</div>
106+
107+
### Adding longer documentation
108+
109+
All of the techniques discussed so far relate to the visual appearance of the flows. In order to add more in depth documentation, something more is needed.
110+
111+
Every node, group and tab can have longer-form documentation added under Description tab in their edit dialog. This help can be formatted using Markdown and including lists, tables and links.
112+
113+
This longer format of documentation is useful where more explanation is needed of a flow's purpose, or some more complex logic needs to be described.
114+
115+
It is also useful where a flow provides an external API of some sort - providing as much detail as it needed for other developers to use the API.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
layout: docs-developing-flows
3+
toc: toc-developing-flows.html
4+
title: Error handling
5+
slug: error handling
6+
---
7+
8+
- How to handle errors in flows
9+
- what can or cannot be caught be a Catch node
10+
- Where Status node can be used
11+
12+
- Layout of Catch/Status nodes in relation to what they target
13+
- Avoiding loops

0 commit comments

Comments
 (0)