What is Raj
Raj solves two problems: state management and running side-effects. These problems are the hardest problems in building client applications.
State management is two things: storing state and handling state transitions. Raj holds a single variable which stores the application state. Raj will update this variable as messages are dispatched. State transitions are synchronous and preferably written in an immutable manner as to be simple to test quickly.
The only way to move state forward is to dispatch messages. All side-effects are functions which may dispatch any number of messages. The view is modeled as a side-effect so it dispatches messages as well. We force the nastiness of side-effects to the edges of the system.
These are two really good problems to solve right off the bat.
How is Raj different from Redux?
Raj was built based on Elm's newer functional programming model, not the functional reactive programming model and was grown and developed using those new language features in application code. Raj is a stricter adaption of the modern Elm architecture.
Raj and Redux have similarities. Both:
- Are agnostic to any particular view layer
- Are quite small frameworks
- Promote a uni-directional data flow
- Move state forward with actions (in Raj "messages")
- Store UI state in a single place (ideally)
- Feature time-travel debugging
Raj differs from Redux in growth complexity.
Redux encourages a structure where as a program grows, more data is put into the top-level state and more actions and reducers are added to an existing list. This growth is O(N). As we add new state, actions, and reducers we need to know the existing list and avoid conflicts. Eventually the mental overhead of these systems requires the addition of new libraries and ways to simulate scope.
In Raj we have isolated "programs" that define independent units of data, logic, and views. These programs are nested and composed in a tree structure. This growth is O(log N). As each individual unit does not need to be aware of any other program's data, logic, or view. Working in a Raj program we can think in terms of localized state, logic, and views.
This decoupling means most feature work for an individual or team can be carried out in parallel. This optimal growth complexity also means we do not need to re-architect or pull in new dependencies as our applications grow. Programs as a unit of application code also enables code reuse as higher-order programs take application composition to a new level.
Redux does not have any particular position on how to handle side-effects and asynchronous effects. There are many competing ways to solve Redux side-effects. Beyond the paradox of choice, many of these solutions lead to bad architectures, are hard to understand, and "work until they don't" meaning eventual rewrites and larger re-architecting as a program or system grows.
Raj has a clear side-effect story built into the framework. Side-effects are functions which dispatch messages. In order to dispatch messages into the system an effect must be given to Raj to be called with a callback to dispatch those messages. These constraints are enough to do side-effects right and cover all use cases.
To summarize, Raj is a stricter adaption of the Elm architecture that provides more compelling and defined stories from both growth complexity and side-effect management.
How is Raj different than Elm?
(Written as of Elm 0.18.)
Elm is a great language everyone should experience, but it does not currently align with business goals that application developers have. Elm is a golden goose not to be tainted by the newest hotness and as such there are many things that cannot be done in Elm without a lot of workaround boilerplate. From a language designer perspective, Elm is doing an amazing job. It's minimal surface area and the seamless way it does solve the problems it chooses is superb. It is definitely a language worth spectating.