Apiumtech Apiumtech Apiumtech Apiumtech
  • ABOUT US
    • CAREERS TEAM
    • PARTNERS
  • SERVICES
    • WEB & MOBILE APP DEVELOPMENT
    • IT TRAINING & CONSULTANCY
    • SOFTWARE ARCHITECTURE
    • UX DESIGN
    • SPRINT ZERO
  • PROJECTS
  • BLOG
  • CONTACT US
Apiumtech Apiumtech
  • ABOUT US
    • CAREERS TEAM
    • PARTNERS
  • SERVICES
    • WEB & MOBILE APP DEVELOPMENT
    • IT TRAINING & CONSULTANCY
    • SOFTWARE ARCHITECTURE
    • UX DESIGN
    • SPRINT ZERO
  • PROJECTS
  • BLOG
  • CONTACT US
Jan 08

Javascript Callback Hell: solved

  • 01/08/2015
  • Christian Ciceri christian
  • No Comments
  • Software architecture
  • Agile methodology, callbackhell, Coding, Javascript, NodeJS

The problem

If you use node.js or some other similar technology, based upon some react-to-events paradigm, you are almost certainly paying a TAX over your developments, the so-called Callback Hell.

Specifically, it’s a TAX you pay everytime you want to separate concerns and give some more layer of indirection, such as when you apply some basic DDD layering. DAOs, Domain Services, Infrastructure Services, and stuff like that.

You want to add some details-hiding interface, and you end up adding steps in the arrow of callbacks.

Otherwise you are paying a “Code Duplication TAX” which is much bigger, to which the Callback TAX is insignificant. But this is a matter for another post.

Another bad side-effect of the Callback TAX is that you have to spread callbacks all over the application, just to be prepared when an implementation goes from sync to async.
For instance, say you can have some DAO that is hiding an in-memory, sync I/O, object cache. If you don’t prepare it for async flow of execution, the migration to an on-disk persistence propagates through all the upstanding layers of indirection.

There are plenty of articles with attempts to solve this problem.
Let’s do a quick review of the more common options.

ASYNC

Async is a library that provides a mean to “verticalize” arrow code:

[code language=”javascript”]
Screen Shot 2016-01-09 at 02.20.19
[/code]

The main problem with async is that the resulting code is complex.
Yes, it’s very “functional style”, it respect the “lambda” aspect of javascript architecture, it allows collaborative “parallel” executions. And.. it’s ugly.
Avoiding nested async is an investment in complexity, lowers readibility, and the result is that programmer is more focused on how to avoid “arrow code” than putting his/her effort in proper, encapsulated design.

PROMISES

The other solution, common in many technologies, are Promises, Futures, Promises/A+, etc.

Let’s see Q promises, a very good implementation that permit chaining, with something like this:

[code language=”javascript”]
Screen Shot 2016-01-09 at 02.13.09
[/code]

It appers to be a better solution than async. Cleaner, simpler. But also tightly coupled.
I have to change all the contracts of my classes, not only the implementations, to use that library of promises.
Try to imagine the cost of changing my promises library to another one. That’s why the Promises/A+ specification.
From this point of view, Promises are a worst solution than async.

But both libraries (async and promises) have an added, deeper, hidden cost that can be dramatic, because of the strong coupling: testability.

There are some more options, like an extensive use of nested closures, or the use of reactive programming extensions, but I think they are solution to different problems; in fact, I think you should not be forced to use them because of the technology you are programming. And in addition, they could be impractical for everyday programming.

The same is true, IMHO, for a massive use of “Tell, Don’t Ask” as an architectural style, like this one; indeed, I see it almost utopical in the vast mayority of the codebases I know, and it’s not so clear that is always the best solution, though it is in a world of pure theory. See for example the related article of Martin Fowler.

ANOTHER POINT OF VIEW

All these solution make big efforts to make the asynchronicity of node.js code easier to understand, to “mitigate” the problem at the same time being respectful to the inner nature of node.js reactor.

My proposal goes in another direction: is really important for a programmer to repeat the callback syntaxis over and over again, only because it’s “node.js programming”? There’s some point in that, some useful side-effect I cannot see? This comes with an cost, that I named here the “Callback TAX”.
OR the reactivity of the underlying technology should tend to be nothing more than an implementation detail, like many others?
What happens if I want to hide the asynchronous nature of an operation behind a common interface, some kind of “syntaxis encapsulation”?

Let’s give a “theoretical framework” to properly name the problem.
It’s perfectly feasible to imagine a “compiler” doing the following, from:

[code language=”javascript”]

Screen Shot 2016-01-09 at 02.13.18

[/code]

to:

[code language=”javascript”]
Screen Shot 2016-01-09 at 02.13.24
[/code]

and further:

[code language=”javascript”]

Screen Shot 2016-01-09 at 02.13.31
[/code]

So we can say this is a mere problem of syntaxis, namely, syntactic noise.
If we could solve the syntactical problem, the code in its whole would be perfectly portable between sync and async technology or implementations.
In fact, in general we can state that every sync code can be written in async style. The contrary is not true.

Syntaxis encapsulation would give me the chance of changing from a sync impementation to an async one, for instance, inside a DAO class, without changing anything of the client code. Not even the syntaxis.

Besides, in the specific case of node.js, I could completely avoid huge (syntactical) problem in testability, and the cost of a bigger codebase.

SOLUTION

Now, I got the bigger part of the work done: identifying a logical framework in which to achieve an optimal solution.
From here it’s only a matter of finding the technology/library/framework nearest to the solution I propose.

Many technologies have a standard solution that goes in this direction. Think for example of C# async/await, Java/Scala continuations, and some Coffee Script solution (IcedCoffeeScript).

In node.js pure javascript style, I found a good solution in a library called wait.for, based upon fiber.
An example:

[code language=”javascript”]

Screen Shot 2016-01-09 at 02.23.11
[/code]

Obviously, it is non-blocking.

No callback syntax, no contract dependencies between client code and server code implementation details, above the logical contract. Sounds like encapsulation.
As you can see, it respects all the constraints of our “theoretical compiler” but the wait.for construct, which it the only coupling (compare it with promises!!); furthermore, it can and should be encapsulated behind some adapter.
If this is a good idea, it won’t be necessary to spend more time in implementing and understanding solutions like promises or futures.
Until the time of writing, this extension shown no problems at all to me, and gave me back the supremacy of design over implementation in node.js without the big associated TAX I was paying.
Remind that we are talking of codebase size and evolution, and its cost of change, which is not hot air, but true loss of productivity 🙂

  • Facebook
  • Twitter
  • Reddit
  • Pinterest
  • Google+
  • LinkedIn
  • E-Mail

About The Author

Related Posts

  • Agile working without borders01/21/2016
  • 15 benefits of software architecture01/11/2016
  • Agile methodology is not only for software development01/04/2016
  • Top benefits of continuous integration12/28/2015

Leave a reply

You must be logged in to post a comment.

JOIN OUR NEWSLETTER

Receive our publication right in your email.





Sending ...

Categories

  • Agile web and app development
  • Apiumtech
  • Events
  • Jobs
  • Offshoring and outsourcing
  • Software architecture
  • Technology industry trends
  • Uncategorized
  • User Experience Design
apiumtech.com Apiumtech is an agile software development company offering services of software architecture, web development, mobile app development, IT consulting, user experience design, bigdata and blockchain

LATEST NEWS

  • Hello world!
  • User experience design infographic
  • Apiumtech’s monthly Newsletter
  • 8 Digital marketing trends in 2016

JOIN OUR NEWSLETTER

    CONTACT INFO

    Av. Doctor Mitjavila 5
    AD500 Andorra la Vella
    Principat d’Andorra
    (+376) 692 2881
    info@apiumtech.com
    © 2022 APIUMTECH SLU. ALL RIGHTS RESERVED.