DEV Community

Cover image for Stream-Oriented Programming: an introduction
Dario Mannu
Dario Mannu

Posted on • Edited on

Stream-Oriented Programming: an introduction

Stream-Oriented Programming (SP, or SOP) is an emerging paradigm that builds upon the principles of Reactive, Declarative, and Dataflow programming. At its core, SP places reactive streams at the centre of software design, providing a unified and powerful model for handling data and events.

Streams can be defined using various primitives, whether imperative or functional. These include Observables, Signals, Callbags, Callforwards, and even plain functions. Among these, Observables are the most mature and feature-rich, and they are currently on the path to becoming a web standard.

The Power of Composition

Reactive streams are inherently composable. They can be grouped into higher-level abstractions that remain consistent in interface and behaviour: data in, data out. This compositional model allows developers to construct complex applications from smaller, reusable units while ensuring consistency and reducing redundancy.

When every part of an application speaks the same language of streams, large-scale systems become easier to build, test, and maintain. The result is a significant reduction in boilerplate code and improved reliability.

Defining a Stream

A reactive stream is not a magical construct but rather a well-structured design pattern. A stream:

  • Accepts data or events as input
  • Optionally processes that data
  • Optionally emits new data as output

This processing can be synchronous or asynchronous, and streams can be composed to aggregate or transform data from other streams. Examples include RxJS’s Subject and BehaviorSubject.

Practical Use Cases

Streams already underpin many real-world systems:

  • Big Data pipelines have long employed similar principles for scalability and throughput.
  • Cloud-native development often applies stream-oriented thinking at the architectural level.
  • User interfaces are a natural fit: everything from button clicks and navigation flows to sequences of modal dialogs can be represented as streams. A mouseover is a stream, a dialog box is a stream, and an entire application can be modelled as a stream.

Despite these natural fits, most mainstream UI frameworks are still primarily imperative in design. SP introduces a novel approach, particularly in web development, by offering a consistent reactive model across the entire stack.

How Streams Simplify Code

In traditional architectures, much effort is spent writing glue code to move data between components:

// glue code
target1.data = source1.data
target2.setData(source2.data)
source3.on('data', data => target.doSomethingWith(data))
Enter fullscreen mode Exit fullscreen mode

With streams, this complexity disappears. You connect streams declaratively, ensuring that type compatibility alone dictates whether the connection is valid. By eliminating these imperative steps, a major source of application bugs is removed.

Working with Streams

The workflow begins by defining streams and then binding them declaratively within templates. The framework handles the wiring automatically:

const Component = () => {
  const stream1 = SomeStream();
  const stream2 = SomeStream();
  const stream3 = SomeStream();

  return rml`
    <button onclick="${stream1}">click me</button>
    <div>${stream2}</div>
    <div class="${stream2}" onmousemove="${stream3}">
      ${stream3}
    </div>
  `;
}
Enter fullscreen mode Exit fullscreen mode

This illustrates the essence of SP: streams are defined first and then composed declaratively in a way that maps directly to user interactions and application logic, often wrapped in a reusable, composable component.

Streams in Action

A concrete example of SP in practice is Rimmel.js, the first UI library designed all around streams.

For live demonstrations, see this Stackblitz collection or explore additional examples. These resources showcase SP principles in action across a wide variety of scenarios.

Future Directions and Challenges

While SP shows remarkable promise, several key challenges and opportunities remain:

  • Standardisation: Observables are moving toward becoming a web standard, but other primitives such as Signals are also evolving. Achieving interoperability might become necessary.
  • Tooling and ecosystem support: The success of SP depends on strong ecosystem adoption. Developer tools, debuggers, and frameworks need to natively support stream concepts.
  • Learning curve: Many developers are familiar with imperative programming. Shifting to a fully declarative, stream-based mindset requires new patterns of thinking and training.
  • Performance considerations: Streams offer clarity, composability and the foundations for excellent performance, but naïve streams implementations might introduce unnecessary overhead or memory issues. Careful optimisation and benchmarking will be essential.
  • Community-driven innovation: SP is shaped by both theory and experimentation. The community’s role in identifying best practices, anti-patterns, and optimal architectures will determine its trajectory.

As these challenges are addressed, SP has the potential to reshape modern software development by providing a consistent, composable, and future-proof programming model.


Learn More

Top comments (0)