Visual coding with Node-RED

Visual coding is a paradigm shift away from editor-based coding to a visually interactive context. With this shift comes new challenges and new approaches to coding.

What does the rectangle mean in terms of code? How do the lines between the rectangles modify the codebase? What do the colours represent or are they just random?

Many are used to drawing shapes and lines but what happens when they suddenly represent the codebase for an application?

I will examine questions in the context of Node-RED: a visual coding environment.

From Code to Shapes

Traditionally coding has involved using a text-based editor to modify lines of code, i.e., instructions that are carried out by a machine. Lines and lines of code make a program that does something useful. A random example of some code:

[...]
    if (a === undefined || a === null) {
      z['re'] =
      z['im'] = 0;
    } else if (b !== undefined) {
      z['re'] = a;
      z['im'] = b;
    } else
      switch (typeof a) {

        case 'object':

          if ('im' in a && 're' in a) {
            z['re'] = a['re'];
            z['im'] = a['im'];
          } else if ('abs' in a && 'arg' in a) {
            if (!Number.isFinite(a['abs']) && Number.isFinite(a['arg'])) {
              return Complex['INFINITY'];
            }
            z['re'] = a['abs'] * Math.cos(a['arg']);
            z['im'] = a['abs'] * Math.sin(a['arg']);
          } else if ('r' in a && 'phi' in a) {
            if (!Number.isFinite(a['r']) && Number.isFinite(a['phi'])) {
              return Complex['INFINITY'];
            }
            z['re'] = a['r'] * Math.cos(a['phi']);
            z['im'] = a['r'] * Math.sin(a['phi']);
          } else if (a.length === 2) { // Quick array check
            z['re'] = a[0];
            z['im'] = a[1];
          } else {
            parser_exit();
          }
          break;
[...]

(Taken from Complex.js)

Code can be more or less understandable but it is always text based. What if that paradigm was changed to a shapes-based programming paradigm? To begin with consider the following diagram:

[
    {
        "id": "14cbf1e76c85869c",
        "type": "inject",
        "z": "156f8ce999bf645b",
        "name": "send data object into flow",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 1741,
        "y": 1544,
        "wires": [
            [
                "3dd9f645df9fbce6"
            ]
        ]
    },
    {
        "id": "a99fd79b7860a2c5",
        "type": "debug",
        "z": "156f8ce999bf645b",
        "name": "debug - display contents of data object",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 2157,
        "y": 1706,
        "wires": []
    },
    {
        "id": "3dd9f645df9fbce6",
        "type": "function",
        "z": "156f8ce999bf645b",
        "name": "say hello world",
        "func": "msg.payload = \"hello world\";\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1924,
        "y": 1631,
        "wires": [
            [
                "a99fd79b7860a2c5"
            ]
        ]
    }
]

Shown are three rectangles joined by two grey lines. Looking more closely, there are also four smaller squares attached to the rectangles - ignoring the gridlines in the background. Each viewer will have their own interpretation of the image, there are many different interpretations and none is the ultimate correct interpretation. We can give it meaning by interpreting the diagram as being a program, a piece of code that does something.

Let us call the connection of the rectangles via the lines at the point of intersection of the rectangles with squares, lets call that whole image a flow. Why a flow? Because we assume that the lines are streams along which data chunks will flow between the rectangles which we will call processes. This is the interpretation of the image in context of flow-based programming.

Flows are visual code, programs that describe the modification of data objects as the data, in the form of messages, travels along the lines connecting the rectangles. In the context of Node-RED, the lines become wires and the rectangles become nodes. Taking the same diagram and adding labels and icons:

[
    {
        "id": "a345c028d1d9b3b6",
        "type": "inject",
        "z": "156f8ce999bf645b",
        "name": "inject message into flow",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 857,
        "y": 1370,
        "wires": [
            [
                "b9a0e040da4ddc17"
            ]
        ]
    },
    {
        "id": "5f0d94fe670a1d1d",
        "type": "debug",
        "z": "156f8ce999bf645b",
        "name": "debug - display contents of data object",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1273,
        "y": 1532,
        "wires": []
    },
    {
        "id": "b9a0e040da4ddc17",
        "type": "function",
        "z": "156f8ce999bf645b",
        "name": "say hello world",
        "func": "msg.payload = \"hello world\";\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 1457,
        "wires": [
            [
                "5f0d94fe670a1d1d"
            ]
        ]
    }
]

It has turned into a typical Node-RED flow, the original image has been reinterpreted in the context of Node-RED. Node-RED is a visual flow-based programming environment, visualising code and programs. Node-RED provides a low-code (i.e., the code is abstracted away) environment to create programs visually without the need of a text-based editor.

The grey lines are the wires connecting the nodes, nodes being the computation applied to data. Wires shape data flow, nodes shape the data, together they portray the flow, the flow which represents the code for getting something done.

Data in the form of messages traverses the flows. Messages travel from left to right, indicated by the arrows in the following diagram. Messages enter a node from the left and exit the node from the right. The modified message continues its journey through the flow.

[
    {
        "id": "a345c028d1d9b3b6",
        "type": "inject",
        "z": "156f8ce999bf645b",
        "name": "inject message into flow",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 857,
        "y": 1370,
        "wires": [
            [
                "b9a0e040da4ddc17"
            ]
        ]
    },
    {
        "id": "5f0d94fe670a1d1d",
        "type": "debug",
        "z": "156f8ce999bf645b",
        "name": "debug - display contents of data object",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1273,
        "y": 1532,
        "wires": []
    },
    {
        "id": "b9a0e040da4ddc17",
        "type": "function",
        "z": "156f8ce999bf645b",
        "name": "say hello world",
        "func": "msg.payload = \"hello world\";\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 1457,
        "wires": [
            [
                "5f0d94fe670a1d1d"
            ]
        ]
    }
]
Note:

arrows are not used in the Node-RED editor; arrows are an extension only used here to provide a visual indication of data flow.

The labels and icon provide a visual cue for better understanding what the flow is doing, more precisely what the nodes are doing to the data that flows through them.

In the context of Node-RED, the flow shown consists of:

The inject node generates an initial message containing a timestamp as payload. Payload is the term given to the contents of the message. Within the Node-RED editor the inject node has a button to trigger the generation of the message, the button is not shown here in the diagram.

Node-RED ensures that the message is passed to the function node, as a Javascript object named msg. The function node executes the following Javascript code upon arrival of the message:

msg.payload = "hello world";

return msg;

Node-REDs convention is that the messages passed into a node are called msg and are a Javascript object. The message is modified by the node with the statement msg.payload = "hello world";, modifying the attribute payload on the data object. The return msg; tells Node-RED that the message can be passed to the debug node. The debug node then displays the contents of the message:

37/17/3023, 17:63:12  node: debug - display contents of data object
msg.payload : string[11]
"hello world"

This is shown in the Node-RED editor in the debug sidebar.

In the end, this flow generate a payload with the string contents of hello world. A basic flow that shows how messages are passed between nodes and how nodes can modify those messages passed to them. I will now explain one other detail shown on the flow diagram, I will do this in the context of Node-RED using its terminology.

Ports and Wires

Ports is the name given to the small squares attached to the nodes. The left hand side of a node is the input side and the right hand side is the output, ports to the left are the input ports and the ports on the right hand side are the output ports. Ports are the points on a node to which the wires can be connected.

Within Node-RED, there is are no limits to the number of wires connected to a node, however the number of ports is limited by a number of constraints. An node may only have zero or one input port, while it can have zero or many output ports. Consider the following flow:

Each node has a different number and type of ports:

Switch nodes are a visual representation of an if statement. Each output node has a statement of comparison that if it matches, the message is sent to the nodes connected to that output node. Node-RED has a collection of core nodes which are documented at the Node-RED documentation site.

Pulling it all together

Humans are dominated by our sense of vision, we can understand concepts far quicker if we have a mental image for a concept. Hence the saying a picture is worth a thousand words. Why should this not be applicable to programming? Flow-based programming offers a alternative paradigm to coding. It uses our visual sense to improve understandability of code and it has the potential to highlight the underlying concepts and context of programs.

It does require a different approach to programming, existing and accepted principles have to be jettisoned to make this approach workable. Visual programming is not everyones cup of tea but equally, it should not be discounted.

Example Flow

FlowHub.org hosts a collection of flows that can be used in Node-RED. There is an introductional flow that can also be imported into Node-RED.

Last updated: 2023-08-28T12:09:57.553Z

Comments powered by giscus

The author is available for Node-RED development and consultancy.