|
1 | | -# GoFlow - Dataflow and Flow-based programming library for Go (golang) |
| 1 | +# GoFlow |
2 | 2 |
|
3 | | -[](https://travis-ci.com/trustmaster/goflow) [](https://codecov.io/gh/trustmaster/goflow) |
| 3 | +[](https://pkg.go.dev/github.com/trustmaster/goflow) |
| 4 | +[](https://golang.org) |
| 5 | +[](https://github.com/trustmaster/goflow/actions/workflows/golangci-lint.yml) |
| 6 | +[](https://codecov.io/gh/trustmaster/goflow) |
4 | 7 |
|
| 8 | +Dataflow and Flow-based programming library for Go. |
5 | 9 |
|
6 | | -### _Status of this branch (WIP)_ |
| 10 | +GoFlow is a lean and opinionated implementation of [Flow-based programming (FBP)](http://en.wikipedia.org/wiki/Flow-based_programming) that lets you design applications as graphs of components reacting to data as it flows through the graph. |
7 | 11 |
|
8 | | -_Warning: you are currently on v1 branch of GoFlow. v1 is a revisit and refactoring of the original GoFlow code which remained almost unchanged for 7 years. This branch is deep **in progress**, no stability guaranteed. API also may change._ |
| 12 | +> **Flow-based programming** is a programming paradigm that defines applications as networks of black-box processes that exchange data across predefined connections by message passing, where the connections are specified externally to the processes. |
9 | 13 |
|
10 | | -- _[More information on v1](https://github.com/trustmaster/goflow/issues/49)_ |
11 | | -- _[Take me back to v0](https://github.com/trustmaster/goflow/tree/v0)_ |
| 14 | +## Features |
12 | 15 |
|
13 | | -_If your code depends on the old implementation, you can build it using [release 0.1](https://github.com/trustmaster/goflow/releases/tag/0.1)._ |
| 16 | +- **Concurrent** — graph nodes run in parallel via goroutines and channels. |
| 17 | +- **Structural** — applications are described as components, their ports, and the connections between them. |
| 18 | +- **Reactive** — system behavior is defined by how components react to events or manage their lifecycle. |
| 19 | +- **Asynchronous by default** — events have no predetermined order unless you enforce one. |
| 20 | +- **Isolated** — communication replaces shared state; components don't share memory. |
14 | 21 |
|
15 | | --- |
| 22 | +## Installation |
16 | 23 |
|
17 | | -GoFlow is a lean and opinionated implementation of [Flow-based programming](http://en.wikipedia.org/wiki/Flow-based_programming) in Go that aims at designing applications as graphs of components which react to data that flows through the graph. |
| 24 | +GoFlow requires Go 1.23 or later. |
18 | 25 |
|
19 | | -The main properties of the proposed model are: |
20 | | - |
21 | | -* Concurrent - graph nodes run in parallel. |
22 | | -* Structural - applications are described as components, their ports and connections between them. |
23 | | -* Reactive/active - system's behavior is how components react to events or how they handle their lifecycle. |
24 | | -* Asynchronous/synchronous - there is no determined order in which events happen, unless you demand for such order. |
25 | | -* Isolated - sharing is done by communication, state is not shared. |
26 | | - |
27 | | -## Getting started |
28 | | - |
29 | | -If you don't have the Go compiler installed, read the official [Go install guide](http://golang.org/doc/install). |
30 | | - |
31 | | -Use go tool to install the package in your packages tree: |
32 | | - |
33 | | -``` |
| 26 | +```bash |
34 | 27 | go get github.com/trustmaster/goflow |
35 | 28 | ``` |
36 | 29 |
|
37 | | -Then you can use it in import section of your Go programs: |
| 30 | +Then import it in your code: |
38 | 31 |
|
39 | 32 | ```go |
40 | 33 | import "github.com/trustmaster/goflow" |
41 | 34 | ``` |
42 | 35 |
|
43 | | -## Basic Example |
| 36 | +## Quick Start |
44 | 37 |
|
45 | | -Below there is a listing of a simple program running a network of two processes. |
| 38 | +Below is a complete program that builds a simple two-component network: one greets names, the other prints the result. |
46 | 39 |
|
47 | 40 |  |
48 | 41 |
|
49 | | -This first one generates greetings for given names, the second one prints them on screen. It demonstrates how components and graphs are defined and how they are embedded into the main program. |
50 | | - |
51 | 42 | ```go |
52 | 43 | package main |
53 | 44 |
|
54 | 45 | import ( |
55 | 46 | "fmt" |
| 47 | + |
56 | 48 | "github.com/trustmaster/goflow" |
57 | 49 | ) |
58 | 50 |
|
59 | | -// Greeter sends greetings |
| 51 | +// Greeter sends greetings. |
60 | 52 | type Greeter struct { |
61 | | - Name <-chan string // input port |
62 | | - Res chan<- string // output port |
| 53 | + Name <-chan string // input port |
| 54 | + Res chan<- string // output port |
63 | 55 | } |
64 | 56 |
|
65 | | -// Process incoming data |
| 57 | +// Process reads incoming names and sends back greetings. |
66 | 58 | func (c *Greeter) Process() { |
67 | | - // Keep reading incoming packets |
68 | 59 | for name := range c.Name { |
69 | | - greeting := fmt.Sprintf("Hello, %s!", name) |
70 | | - // Send the greeting to the output port |
71 | | - c.Res <- greeting |
| 60 | + c.Res <- fmt.Sprintf("Hello, %s!", name) |
72 | 61 | } |
73 | 62 | } |
74 | 63 |
|
75 | | -// Printer prints its input on screen |
| 64 | +// Printer prints its input on screen. |
76 | 65 | type Printer struct { |
77 | | - Line <-chan string // inport |
| 66 | + Line <-chan string // input port |
78 | 67 | } |
79 | 68 |
|
80 | | -// Process prints a line when it gets it |
| 69 | +// Process reads lines and prints them. |
81 | 70 | func (c *Printer) Process() { |
82 | 71 | for line := range c.Line { |
83 | 72 | fmt.Println(line) |
84 | 73 | } |
85 | 74 | } |
86 | 75 |
|
87 | | -// NewGreetingApp defines the app graph |
| 76 | +// NewGreetingApp defines the application graph. |
88 | 77 | func NewGreetingApp() *goflow.Graph { |
89 | 78 | n := goflow.NewGraph() |
90 | | - // Add processes to the network |
91 | 79 | n.Add("greeter", new(Greeter)) |
92 | 80 | n.Add("printer", new(Printer)) |
93 | | - // Connect them with a channel |
94 | 81 | n.Connect("greeter", "Res", "printer", "Line") |
95 | | - // Our net has 1 inport mapped to greeter.Name |
96 | 82 | n.MapInPort("In", "greeter", "Name") |
97 | 83 | return n |
98 | 84 | } |
99 | 85 |
|
100 | 86 | func main() { |
101 | | - // Create the network |
102 | 87 | net := NewGreetingApp() |
103 | | - // We need a channel to talk to it |
104 | 88 | in := make(chan string) |
105 | 89 | net.SetInPort("In", in) |
106 | | - // Run the net |
| 90 | + |
107 | 91 | wait := goflow.Run(net) |
108 | | - // Now we can send some names and see what happens |
| 92 | + |
109 | 93 | in <- "John" |
110 | 94 | in <- "Boris" |
111 | 95 | in <- "Hanna" |
112 | | - // Send end of input |
113 | 96 | close(in) |
114 | | - // Wait until the net has completed its job |
| 97 | + |
115 | 98 | <-wait |
116 | 99 | } |
117 | 100 | ``` |
118 | 101 |
|
119 | | -Looks a bit heavy for such a simple task but FBP is aimed at a bit more complex things than just printing on screen. So in more complex an realistic examples the infractructure pays the price. |
120 | | - |
121 | | -You probably have one question left even after reading the comments in code: why do we need to wait for the finish signal? This is because flow-based world is asynchronous and while you expect things to happen in the same sequence as they are in main(), during runtime they don't necessarily follow the same order and the application might terminate before the network has done its job. To avoid this confusion we listen for a signal on network's `wait` channel which is sent when the network finishes its job. |
| 102 | +> **Why the `wait` channel?** The flow-based world is asynchronous — events don't necessarily happen in the order they were sent. The `wait` channel signals when the network has fully completed, preventing premature program termination. |
122 | 103 |
|
123 | 104 | ## Terminology |
124 | 105 |
|
125 | | -Here are some Flow-based programming terms used in GoFlow: |
126 | | - |
127 | | -* Component - the basic element that processes data. Its structure consists of input and output ports and state fields. Its behavior is the set of event handlers. In OOP terms Component is a Class. |
128 | | -* Connection - a link between 2 ports in the graph. In Go it is a channel of specific type. |
129 | | -* Graph - components and connections between them, forming a higher level entity. Graphs may represent composite components or entire applications. In OOP terms Graph is a Class. |
130 | | -* Network - is a Graph instance running in memory. In OOP terms a Network is an object of Graph class. |
131 | | -* Port - is a property of a Component or Graph through which it communicates with the outer world. There are input ports (Inports) and output ports (Outports). For GoFlow components it is a channel field. |
132 | | -* Process - is a Component instance running in memory. In OOP terms a Process is an object of Component class. |
| 106 | +| Term | Description | |
| 107 | +|-----------|-------------| |
| 108 | +| **Component** | The basic processing element. Its structure consists of input/output ports and state fields; its behavior is defined by event handlers. Analogous to a Class. | |
| 109 | +| **Connection** | A link between two ports in the graph. In GoFlow this is a typed channel. | |
| 110 | +| **Graph** | A higher-level entity composed of components and connections. Can represent composite components or entire applications. Analogous to a Class. | |
| 111 | +| **Network** | A running instance of a Graph. Analogous to an Object. | |
| 112 | +| **Port** | A property through which a Component or Graph communicates with the outside world (input/output). In GoFlow this is a channel field. | |
| 113 | +| **Process** | A running instance of a Component. Analogous to an Object. | |
133 | 114 |
|
134 | | -More terms can be found in [Flow-based Wiki Terms](https://github.com/flowbased/flowbased.org/wiki/Terminology) and [FBP wiki](http://www.jpaulmorrison.com/cgi-bin/wiki.pl?action=index). |
| 115 | +More terms can be found in the [Flowbased.org Terminology](https://github.com/flowbased/flowbased.org/wiki/Terminology) and the [FBP wiki](http://www.jpaulmorrison.com/cgi-bin/wiki.pl?action=index). |
135 | 116 |
|
136 | 117 | ## Documentation |
137 | 118 |
|
138 | | -### Contents |
139 | | - |
140 | | -1. [Components](https://github.com/trustmaster/goflow/wiki/Components) |
141 | | - 1. [Ports and Events](https://github.com/trustmaster/goflow/wiki/Components#ports-and-events) |
142 | | - 2. [Process](https://github.com/trustmaster/goflow/wiki/Components#process) |
143 | | - 3. [State](https://github.com/trustmaster/goflow/wiki/Components#state) |
144 | | -2. [Graphs](https://github.com/trustmaster/goflow/wiki/Graphs) |
145 | | - 1. [Structure definition](https://github.com/trustmaster/goflow/wiki/Graphs#structure-definition) |
146 | | - 2. [Behavior](https://github.com/trustmaster/goflow/wiki/Graphs#behavior) |
| 119 | +### Wiki |
147 | 120 |
|
148 | | -### Package docs |
| 121 | +- [Components](https://github.com/trustmaster/goflow/wiki/Components) — ports, events, process, and state. |
| 122 | +- [Graphs](https://github.com/trustmaster/goflow/wiki/Graphs) — structure definition and behavior. |
149 | 123 |
|
150 | | -Documentation for the flow package can be accessed using standard godoc tool, e.g. |
| 124 | +### GoDoc |
151 | 125 |
|
| 126 | +```bash |
| 127 | +go doc github.com/trustmaster/goflow |
152 | 128 | ``` |
153 | | -godoc github.com/trustmaster/goflow |
154 | | -``` |
155 | 129 |
|
156 | | -## Links |
| 130 | +Or view the [online reference](https://pkg.go.dev/github.com/trustmaster/goflow). |
| 131 | + |
| 132 | +## Related Projects |
| 133 | + |
| 134 | +- [Flow-based.org](https://github.com/flowbased/flowbased.org/wiki) — specifications and recommendations for FBP systems. |
| 135 | +- [J. Paul Morrison's Flow-Based Programming](https://jpaulm.github.io/fbp/index.html) — the origin of FBP, including [JavaFBP](https://github.com/jpaulm/javafbp), [C#FBP](https://github.com/jpaulm/csharpfbp), and the [DrawFBP](https://github.com/jpaulm/drawfbp) diagramming tool. |
| 136 | +- [NoFlo](http://noflojs.org/) — FBP for JavaScript and Node.js. |
157 | 137 |
|
158 | | -Here are related projects and resources: |
| 138 | +## Roadmap |
159 | 139 |
|
160 | | -* [Flowbased.org](https://github.com/flowbased/flowbased.org/wiki), specifications and recommendations for FBP systems. |
161 | | -* [J. Paul Morrison's Flow-Based Programming](https://jpaulm.github.io/fbp/index.html), the origin of FBP, [JavaFBP](https://github.com/jpaulm/javafbp), [C#FBP](https://github.com/jpaulm/csharpfbp) and [DrawFBP](https://github.com/jpaulm/drawfbp) diagramming tool. |
162 | | -* [NoFlo](http://noflojs.org/), FBP for JavaScript and Node.js |
163 | | -* [Go](http://golang.org/), the Go programming language |
| 140 | +- Integration with NoFlo-UI / Flowhub (in progress) |
| 141 | +- Distributed networks via TCP/IP and UDP |
| 142 | +- Reflection and monitoring of networks |
| 143 | + |
| 144 | +## Contributing |
| 145 | + |
| 146 | +Contributions are welcome! Please open an issue or pull request on [GitHub](https://github.com/trustmaster/goflow). |
| 147 | + |
| 148 | +Before submitting changes, make sure your code passes the linter and tests: |
| 149 | + |
| 150 | +```bash |
| 151 | +golangci-lint run ./... |
| 152 | +go test -v -race ./... |
| 153 | +``` |
164 | 154 |
|
165 | | -## TODO |
| 155 | +## License |
166 | 156 |
|
167 | | -* Integration with NoFlo-UI/Flowhub (in progress) |
168 | | -* Distributed networks via TCP/IP and UDP |
169 | | -* Reflection and monitoring of networks |
| 157 | +[MIT](LICENSE) |
0 commit comments