The New Dawn of functional reactive programming in Node.js - Marble.js 2.0
We all want to make our products more responsive and better performing. We all want to deliver a smooth user experience without freezing and slowing down. Reactive programming is not just a buzzword but nowadays is a de facto standard for building web apps on the frontend. On the backend, the concept is still not so popular as we might think. The Marble.js framework comes as a response to that need and offers a way of building scalable and functional products with reactive data flow in mind.
The core philosophy
Marble.js is a functional reactive framework built on top of the Node.js platform. The core concept assumes that almost everything is treated as a stream of events passing through over time. If you come from a functional programming world you might notice that the framework draws on many functional programming concepts. The purely functional languages like Haskell express side effects such as I/O and other stateful computations using monadic actions.
With the growing popularity of reactive extensions, with Marble.js you can create a referential transparent program specification made up of just functions that may produce side effects, like networking, logging, database access, etc. Using its monadic nature we can map I/O operations over effects and bring in other sequences of operations.
Because it is a functional reactive framework, RxJS is the first class citizen here. Despite the single event nature of basic HTTP, there are are no contraindications against using it for single events. In Marble, RxJS is used as a hammer for expressing asynchronous flow in a monadic manner, even if you have to deal with only one event occurring over time.
The framework doesn’t operate over basic protocol only but can be used also for both WebSocket and event sourcing purposes, where its multi-event nature shows its claws.
Everything is a stream
The main building block of the whole framework is an Effect, which is just a function that operates over a stream of events.
Marble.js abstracts this concept in a way that can be applied in many different scenarios - from a very basic REST API to a feature-rich real-time WebSocket-based system.
As previously mentioned, Marble.js defines a common functional interface for many different kinds of Effects. Combined with a unidirectional data flow, it provides predictability and traceability of the events passing through.
Thanks to that, it makes the framework consistent across the different areas that it needs to operate on.
If we look at the WebSocket protocol and try to apply the reactive programming concepts under the same core principles defined by the framework, we can achieve a coherent environment for dealing with asynchronous events passing over time.
The powerful set of features
From the very first version, Marble.js was built as a middleware-based system. It is a common requirement to encounter the necessity of having various operations needed around incoming data.
In Marble.js, as with any other Effect, the middleware is a stream of side-effects that can be composed and plugged into our incoming data lifecycle to perform certain actions before reaching the designated point.
The second major release takes even bigger steps toward being a fully featured framework. Besides the fluent API for working between different protocols (such as WebSockets) one of the main goals of the newest release was to increase the type safety and improve data type inference within Effects.
With Marble.js you can validate and check at runtime that incoming data has the shape that you would expect. With the deep integration of the io-ts library, you can even extract a static type from validator that is guaranteed to match any data structure that passes validation.
The functional nature does not stand in the way of proposing its own mechanism for implementing a Dependency Injection (DI) system. It is a very simple concept which can be implemented in many different ways.
Based on the need to provide different modules on demand, Marble.js comes at the DI problem from a different, more functional direction, potentially very similar to other popular pure functional implementations. From version 2.0, it introduces a Context - an abstraction over the Reader monad.
Building a framework or even a bigger library is not something you can do overnight. It is always a process with a clear philosophy behind it. At first, Marble.js was born as an HTTP middleware library for Node.js.
Applying lean startup principles to an open source product is not something you see very often, but in practice, a lot of popular open source projects were born with lean startup principles in mind, even if the authors didn’t realize.
Starting from the market analysis, in just a one week, Marble had a working proof of concept that tried to combine a reactive programming paradigm with the event nature of HTTP protocol.
After just one more week it was presented as an open source MVP product to a wider audience on GitHub. The initial concept was validated in the beta phase and was iterated with new ideas and improvements from version to version.
Besides that, it gains its fair share of exposure on social media, getting attention from, among others, Ben Lesh (the RxJS project lead) who gave a big shot of support from the very beginning.
With such interest in the presented concept, Marble.js got a big response with a bunch of proposed improvements and cool ideas from the community. The second major version, released on the 2nd of March, is an acknowledgment of the trust that the community gave from the very beginning.
Share this article: