
Nonsense Accusations of Spaghetti Code Considered Harmful - rtfeldman
http://rtfeldman.com/post/34886239691/nonsense-accusations-of-spaghetti-code-considered
======
shadowmint
The author says it himself:

> Haskell code sucks, therefore Haskell sucks.” No, poorly organized code
> sucks. If that code happens to be written in Haskell, don’t shoot the
> messenger.

Basically, yes.

Not all callbacks are harmful. Not all goto's are harmful either; you _can_
write both elegant and maintainable code using both.

 _That_ is not that point. It's like saying you can write elegant and
maintainable code in assembly. Yes you can (no, really. I've actually seen
some. :P)... but _tangibly_ in _real world situation_ is that how it _usually_
plays out?

By tacitly (some might argue expressly even...) supporting callbacks, are
these modern frameworks leading to _in general_ an improvement in code quality
or a _drop_ in code quality, compared to the non-callback based code.

That isn't an intangible. It's empirically measurable, and I'd love to see
some code metrics off git hub that measured it.

Waxing lyrical about how how callbacks can be used for the Forces of Good by
Clever Programmers doesn't really impress me. So can auto-generated xsd -> C#
code (I suppose) in the right circumstances.

Less arm-chair talking on both sides please; back your assertion up with some
data.

~~~
jrajav
Can this elegant and maintainable assembly code be found online anywhere, and
do you remember where? I've just started to pick up nasm and armv7, and I'm
very interested.

~~~
throwaway64
you might want to take a look at MenuetOS, its written in x86 assembly, and
expressly created for clarity and learning.

<http://www.menuetos.net/>

------
peterhunt
Oh come on. You've set up several straw man arguments here that don't apply to
the real world situations that give rise to callback hell, like fetching
multiple rounds of data and aggregating many parallel callbacks at each step,
or callbacks that are difficult to trace the origin of. Sure you can write
good code with callbacks -- you can also write good code with goto and callcc
-- but building a better abstraction makes code easier to write and maintain.

~~~
raganwald
So, what we have here are:

a. Post #1 gives strawman/overly simplistic argument for why callbacks are
hell and FRP is great, and obscures example by comparing crappy syntax to
elegant syntax.

b. Post #2 gives straw man/overly simplistic argument for why callbacks are
fine, and correctly points out the syntax issue.

My takeaway is that both posts have some merit, but what we really need are
some examples that go Apples to Apples on syntax AND show when callbacks are
fine and when they aren't. Along with some realistic discussion of the
complexity inherent in things like aggregating callbacks.

Because, you know, we can only eliminate so much accidental complexity, and
then we'll run into inherent complexity. And speaking as a fellow who appeals
to authority by mentioning his experience writing a tool that did runtime
analysis of multi-threaded applications... There is a lot of inherent
complexity involved in writing truly asynchronous and parallel code when
failure is expected.

------
ybaumes
I will talk about my own experience, and it only engage myself. I am not sure
we can generalize my experience here with callbacks: But for me callback
resulted in a big mess. :-)

I've worked in two investment banks, working on their "order passing servers"
legacy code. It's c++ code for unix platform. And of course select() driven
implementation leads to extensive use of callbacks. The kind of code structure
was the same every where I worked: I receive something on a socket, I decode
it, what is the event type? Huh ok, I call then the corresponding callback...
Huh I need to load the associated context too. And usually the spaghetti
appears just right here. When writing the callback for a processing deep into
the "sequence diagram" people tend to be overflowed by information. They don't
have a clear view of the invariants in their mind. Which leads to over-
complicated code in order to deal with the myriad of possible states of your
context. And it leads to a lot of bugs.

The context being global, a callback function is forced to behave with side
effects. I guess (and only guess since I've never had the occasion to work in
FRP style yet) that writing a callback in a synchronous style would would
favor a more Functional-programming style, avoiding a lot of buggy side
effects, while I guess also it would not be possible to avoid them all... :-/
It must be verified in a real world project that FRP does lead to a cleaner
code. Does someone have examples please?

It would be great to have a c++ framework implementing FRP. Or implementing
the async/await keywords as in c#. (just tell me if I am not clear enough
cause I am not a natural English speaker... :-) )

------
olalonde
I'm surprised the author doesn't mention the async library[0] to avoid
callback hell. Also, he should probably have mentioned "continuation passing
style"[1] as it is the term for that style of programming.

[0] <https://github.com/caolan/async>

[1] <https://en.wikipedia.org/wiki/Continuation-passing_style>

------
ddellacosta
Yeah, I've got to agree. Reading the original article ("Escape from Callback
Hell" with the subtitle "Callbacks are the modern goto"), it starts with this:

 _Callbacks are used to structure programs. They let us say, “When this value
is ready, go to another function and run that.” From there, maybe you go to
another function and run that too. Pretty soon you are jumping around the
whole codebase._

So, essentially this sounds like the author is saying functional programming
is considered harmful. Which, on the face of it is not true.

Of course you can write spaghetti code in any paradigm and using any
technique. The whole point of callbacks (and passing functions around as
values, more generally) is that you have one more tool in your toolbox to
achieve things that are difficult otherwise. Suggesting they are harmful in
such a hyperbolic way is throwing the proverbial baby out with the bathwater.

I'm sure there's a case to be made for properly structuring a callback-heavy
application, but methinks a more nuanced approach may be in order here (and in
general... _sigh_ ).

------
fauigerzigerk
_> However, I also like honesty._

Me too, but calling your opponent dishonest just because you disagree is
something I don't like at all.

My own opinion is that expressing logically synchronous statements in terms of
asynchronous callbacks is always going to be more complex than using an
implicitly synchronous sequence of statements. Not because indentation is so
complex, but because there are more moving parts to consider when you make
something explicit that was implicit before.

This difference in complexity for logically synchronous statements is not a
matter of taste, unless you deny that having more variables is more complex
than having fewer variables.

------
bilalq
None of the examples presented were that bad. However, things can get pretty
hairy when you start requiring CommonJS modules and have callbacks being
passed to functions in different files.

------
Xion
The author argues that callbacks do not necessarily impact code's readability
in a negative way. However, he does so while presenting examples in
CoffeeScript, a language where reduction of the usual JS callback boilerplate
(`function() { ... }`) is one of the main perks.

In other words, he claims there is no issue by presenting a possible solution
to it.

~~~
raganwald
His argument is that callback the semantic construct != nested brace hell the
syntactic construct.

Elm presents a new syntactic construct AND a new semantic construct. His
example serves to demonstrate that the syntactic construct by itself is
sufficient for many cases, which suggests that the original article might have
been better served by being about Elm's syntax instead of bashing on the
semantic construct.

------
jesstaa
If you write good code then callbacks aren't a problem. Gotos also aren't a
problem if you write good code.

~~~
DanWaterworth
The thing that gotos and callbacks have in common is that they are both
extremely powerful. The problem is not that you can't write good code with
either construct, it's that you can write bad code.

Abstraction is the process of creating self imposed restraints in order to aid
reasoning. Using powerful features like callbacks and gotos is in some sense
its polar opposite

------
pfortuny
On a side note, everybody quotes Dijkstra but what about Knuth's Structured
Programming with goto?

[https://cs.sjsu.edu/~mak/CS185C/KnuthStructuredProgrammingGo...](https://cs.sjsu.edu/~mak/CS185C/KnuthStructuredProgrammingGoTo.pdf)

------
aufreak3
I think the "callbacks lead to spaghetti code" view is just an inadequate
expression of the problem. I believe that people who are averse to callbacks
feel so because callback-ridden code doesn't compose well. Compose-ability is
an important practical consideration, but many async libraries solve this
problem to a fair extent.

Also, reactive programming is not exactly the solution to callbacks like
structured programming is to goto. "B needs to update automatically when A
changes" criterion is extraneous to the problem.

------
kghose
Code is a dry, dry topic. This article made me smile, smile wider and then
LOL. This is one of the few articles on code that are very well written,
informative and brightening.

------
louischatriot
The author of "Escape from callback hell" goes indeed too far. This is of
course a matter of opinion, but I found that 3 levels of nesting (in
javascript for nodejs) is usually perfectly acceptable and readable. If there
are more than 3, I use async to get a nice, linear looking flow.

------
antihero
This kind of misses the point - sure it's still simple for a four line
function, but it's whether callback oriented code _scales_ for anything other
than the most simple of projects.

~~~
jrajav
It does scale. I can vouch for it from personal experience. The smell is when
you start constructing elaborate pyramids - but in that case, the callbacks
are not to blame, you are for not making your processing code modular with
well-defined, pluggable functions defined before the main async flow. None of
the examples were long enough to merit separate function definitions, but he
doesn't ignore the point:

> Let’s assume that it’s good practice to organize your program into simple
> functions that have as few side effects as possible.

> There is no law against writing simple, concise callbacks that defer to
> well-organized, side-effect-free functions for complex processing. In fact,
> I’d recommend using them in precisely that way.

------
guilloche
callbacks are not desirable, and duplicated codes are much worse. Are there
any other effective ways to reduce duplicates?

------
bobdole2
Yeah!

