----
-layout: post
-title: "Fluorine: the library to get things flowing"
-tags: english javascript
-color: cyan
-header_image: fluorine.gif
-description: "Fluorine is a flow based library that makes complex
-async operations really simple."
----
-
-Today I was happily surprised with the fact that [fluorine ][fluorine]
-has been made publicly available with an MIT License!
-This is a library created by [azendal][azendal]
-as a way to solve some of the more complex flows in [breezi][breezi].
-The problem had been bugging us for a while and the several existing
-solutions to the async problem didn't feel right for it, and then
-fluorine arrived to the [neon][neon] [family][cobalt] [of][thulium]
-[libraries][tellurium].
-
-Fluorine is a really simple flow abstraction for javascript that doesn't
-do much: You can have a *Flow*, which has a series *Steps*; a step has a
-name, a list of dependencies, and a fulfill function. The way it works
-is that flows run automatically, and every step that can be taken *is
-taken*, then its dependents are executed, and so on until all nodes are
-fulfilled. That's all there is to it, and that's all it needs to provide
-powerful asynchronous constructs that can stay decoupled.
-
-But let's code a simple example:
-
-In the following example we're loading an application where we allow our
-user to view a 3D model of their favorite 1985 vintage action figures in
-a fake shelf. We *show a loading screen* while we *get the data for the
-models*, then *fetch the models themselves*, also *request the user data*
-(so we can see their favorites), plus *all the latest posts* from the most
-popular social network for enthusiasts of 1985 vintage action figures
-— G.I. Yo. Once we have the model and user data, we can *display the shelf*
-so the user can see the name of 1985 snowman and finally settle that argument
-with joe about which 1985 vintage action figure is the best 1985 vintage
-action figure, so we have to: *hide the loading scren*, show the models
-with a generic image and *leave a loader in the social network box*.
-Once the models are fetched, we can start *displaying them* in the shelf
-instead of the generic image while it loaded; once we have the social
-networks, we *put the posts in there*. So, that's easy right?, no chance
-of turning *this* into a mess...
-
-![A boring old diagram][fig1]
-*34 indentations later...*
-
-I put this in a diagram with handy color coded arrows so we don't get
-lost. Now we know what operations depend on each other, and that's all we
-need for fluorine. So, we can now turn that diagram into a flow:
-
-<pre class="language-javascript"><code class="language-javascript">
- var giFlow = new Flow();
-
- // Top Row Nodes (as shown in the diagram)
-
- giFlow.step('showLoadingScreen')(function (step) {
- loadingScreen.show();
- step.success();
- });
-
- giFlow.step('fetchUserData')(function (step) {
- UserData.fetch(function (userData) {
- step.success(userData);
- });
- });
-
- giFlow.step('fetchModelData')(function (step) {
- ModelData.fetch(function (modelData) {
- step.success(modelData);
- });
- });
-
- giFlow.step('fetchSocialData')(function (step) {
- SocialData.fetch(function (socialData) {
- step.success(socialData);
- });
- });
-
- // Middle Row Nodes (as shown in the diagram)
-
- giFlow.step('hideLoadingScreen').dependsOn('showLoadingScreen', 'fetchUserData', 'fetchModelData')(function (step) {
- loadingScreen.hide();
- step.success();
- });
-
- giFlow.step('displayPlaceholderSocialBox').dependsOn('fetchUserData', 'fetchModelData')(function (step) {
- socialBox.display(function () {
- step.success();
- });
- });
-
- giFlow.step('displayModelShelf').dependsOn('fetchUserData', 'fetchModelData')(function (step) {
- modelShelf.display(step.data.fetchUserData, step.data.fetchModelData, function () {
- step.success();
- });
- });
-
- giFlow.step('fetchModels').dependsOn('fetchModelData')(function (step) {
- Model.fetch(step.data.fetchModelData, function () {
- step.success();
- });
- });
-
- // Bottom Row Nodes (as shown in the diagram)
-
- giFlow.step('fillInGIYoPosts').dependsOn('fetchSocialData', 'displayPlaceholderSocialBox')(function (step) {
- socialBox.fillInGIYOPosts(step.data.fetchSocialData, function () {
- step.success();
- });
- });
-
- giFlow.step('replaceModels').dependsOn('fetchModels', 'displayModelShelf')(function (step) {
- modelShelf.replaceModels(step.data.fetchModels, function () {
- step.success();
- });
- });
-</code></pre>
-
-That's all there is to fluorine: you define steps, you fulfill them.
-Every step may have dependents, and it can access their data from the
-callback! Now you can define complex operations step by step, you could
-create complex branching by not triggering a step's success method.
-Another important part of fluorine is that modifying flows is really
-easy, as long as you have clearly defined nodes, you can just move
-around dependencies to alter the way the program runs!
-You can even check your work against the spec by converting it
-to dot format (eg. `giFlow.toDot()`):
-
- digraph {
- showLoadingScreen
- fetchUserData
- fetchModelData
- fetchSocialData
- hideLoadingScreen
- showLoadingScreen -> hideLoadingScreen
- fetchUserData -> hideLoadingScreen
- fetchModelData -> hideLoadingScreen
- displayPlaceholderSocialBox
- fetchUserData -> displayPlaceholderSocialBox
- fetchModelData -> displayPlaceholderSocialBox
- displayModelShelf
- fetchUserData -> displayModelShelf
- fetchModelData -> displayModelShelf
- fetchModels
- fetchModelData -> fetchModels
- fillInGIYoPosts
- fetchSocialData -> fillInGIYoPosts
- displayPlaceholderSocialBox -> fillInGIYoPosts
- replaceModels
- fetchModels -> replaceModels
- displayModelShelf -> replaceModels
- }
-
- dot -Tpng that_file_up_there.dot -o fancy_graphic.png
-
-![Fancy Graphic][fig2]
-
-They look the same (ish)! It even did a better job at putting it together!
-
-So that's fluorine, a pretty simple flow tool that can let you build
-complex stuff, you could implement a neural network, or a behavior tree
-for a game actor, or a loop of events, or do some complex distributed
-tasks, you can use it for almost anything as long as you can graph it,
-because that's all it really is: graphs. You could even create dynamic
-nodes and have a flow that is created programatically!
-
-I hope that example was enough to get you interested on how you can use
-it now that it's open to everyone! Have fun :D
-
-[fluorine]: https://github.com/freshout-dev/fluorine
-[azendal]: https://github.com/azendal
-[breezi]: https://breezi.com
-[neon]: https://azendal.github.io/neon
-[cobalt]: https://github.com/rbdr/cobalt
-[thulium]: https://freshout-dev.github.io/thulium
-[tellurium]: https://github.com/azendal/tellurium
-[fig1]: https://docs.google.com/drawings/d/1a3xVTO0qfSqt_fKWuKzeQFGbtOvQbfVV63_nGD5xcq0/pub?w=960&h=720
-[fig2]: /img/fluorine.png