Decatronics

Flow Tasks

Embedding the power of flowcharts into complex algorithm design.

Simple things should be simple, and complex things should be possible.
-Alan Kay

Flowchart example

Figure 1: Decentralized node operating procedure.

Introduction


What are Flow Tasks?

In software, the need often arises for a system that needs to handle a complex procedure. Traditional methods of functional decomposition and object oriented design are more than enough to tackle these sorts of systems, at the cost of significant design effort.

Flow tasks are an algorithm and data structure collection that aim to reduce design effort. In simple terms, flow tasks provide a near-exact mapping from a flowchart based system design, into written software.

Definitions:

  • Flow task — a single task a system must perform (analogue: a flowchart element)
  • Flow — a set of flow tasks working together (analogue: a flowchart)
  • Flow task manager — a software implementation of the above two concepts

Motivations for Using Flow Tasks

Flow tasks, like any other specialist tool, are suited to specific types of problems. For systems well represented as a non-linear series of tasks and states, flow tasks are a suitable design option. Think of flow tasks like a state machine, but written in object-oriented style with more advanced flow control.

When a system becomes sufficiently complicated, the following benefits of flow tasks are immediately realizable:

  • Self-documenting — the correct way to use flow tasks is to put a flowchart together before writing any code. It is quicker to make drastic system architecture changes on a diagram than to edit the written code.
  • Anything is possible — if a process is describable, it can be implemented with flow tasks.
  • Clear communication — non-developers can easily understand the system diagram.
  • Quick updates — with this design technique, the entire system structure is forced to be modularized. Making major changes to the system structure is simple, even during runtime.
  • Parallelism — flow tasks can be extended to run parallel tasks across multiple threads.
  • Substructure — flow tasks in a specific flow can be delegated to other flows.
  • Efficient to Interrupt — tasks are re-entrant, and can yield when there is no work to do.

Using Flow Tasks


For example, consider this simple system:

Simple flowchart

Such a system is trivial to implement without additional frameworks.

However, consider if just one of the tasks was much more complicated than the rest. For example, suppose the "check sensors" task had a 100ms critical deadline, and involved multiple network calls (each taking up to 80ms) which update various state tables that feed a complex sensor fusion algorithm, itself depending on historical data.

This system would be challenging to implement in typical functional or object-oriented style. By sacrificing coding time for design time, and adding a layer of abstraction by implementing flow tasks, the software becomes relatively simple — almost as trivial as in the first system.

Something like this:

Complex sensor flowchart

In the above diagram, boxes represent individual flow tasks - some of which occur simultaneously in separate threads. This is a hypothetical design that could apply to many kinds of "smart" devices. Here are the important elements from this example:

  • Multithreading kicks off after hardware is woken up (presumably from a low-power mode). Consider the code running before threading as a "prefix flow task".
  • The TCP/IP and GPS calls timeout at the same time. To contrast, the local sensors on the CAN bus run through to the state table separate from the GPS and TCP/IP responses.
  • Sensor fusion and sleeping the hardware happens as a "postfix flow task".

The complexity that marries this design particularly well to flow tasks is four-fold:

  • The system design will involve a flow chart regardless, because software deadlines need to be considered. Since the design is already present in a flow chart, converting it into code is efficient when leveraging the one-to-one mapping provided by flow tasks.
  • Each network call has variable return timing, which warrants processing straight away. Perhaps a standard callback scenario is acceptable, but a GPS call is re-entrant, so state must persist between calls and callbacks (not always easy to do!).
  • Network calls all follow a similar filter-through process that resolves into sensor data. The three calls can be abstracted as a single flow task that is reused for any number and type of network call. This provides greater flexibility for adding or updating data-streams.
  • Thread modularity is extendable with minimal modification to the prefix and postfix tasks, because the threading is separated from them by design.

In this example, the exact implementation details are not covered. Rather, consider the design process: separate the system into blocks of work, then link them in a non-linear fashion, and track their running with encapsulated state and a well-defined data flow direction.

This is precisely what flow tasks are designed for.

Flow Tasks - Implementation


Any flow tasks implementation consists of three major elements:

  1. Task Manager — Stores a table of tasks and tracks the current task that is executing.
  2. Task Method — An object for representing a task with it's properties and algorithms.
  3. State Controller — The state machine that backs all flow task implementations.

Task managers need to do the following:

  1. Add and remove tasks from the table
  2. Adjust the order of tasks
  3. Call the current task, so it can update the flow
  4. Return information about the running state of the flow

Tasks should have the ability to do the following:

  1. Hold at the current task
  2. Move to the next/previous task
  3. Timeout with reset, next, previous or jump
  4. Jump to another task
  5. End the flow
  6. Reset the flow

All the above functionality can be implemented in any way that suits the platform, but will almost certainly involve a state machine of some kind.

Example Implementation in C#

If you want to see what an implementation of flow tasks is like, here's a rudimentary effort in C#:

All the diagrams in this article were produced with the amazing online drawing tool, draw.io

That is all for this introduction to the principle of flow tasks!
I look forward to using these ideas in future projects and designs.