4 ms·
I wholeheartedly agree with you that the comment "No one actually writes code like this" was inaccurate and not useful for the discussion. I see people doing t
by raggi 16y ago
I wholeheartedly agree with you that the comment "No one actually writes code like this" was inaccurate and not useful for the discussion.
I see people doing this exact same style of code in EventMachine in ruby, and have done for years. I am continually having to advise newcomers to the evented space that they need to write state machines inside objects to maintain state and process flow, and advising them to wrap callbacks into message sends to these process containers.
There is nothing lacking in javascript to do this (create state and function containers), just as there is no lack of OO in ruby. Despite this, newcomers to evented programming always do the same thing. They revert back to a primitive style of programming, writing very long, very tab-deep functions. This is bad practice, you don't do it in an imperative synchronous environment (after some experience), and you shouldn't do it in an async environment.
You do not need to use closures for state passing. You shouldn't use closures as general state containers. They're even worse than using stack frames, as they're even less easy to debug (at least walking stack frames is easy with a decent debugger). They're really useful for the minor things, but to encode a complex process, they're completely inappropriate for reasons already discussed (error handling is an ever so common one in the network space).
I think this may be what the person was trying to get at with their comment, but they completely lacked substance, which was no use to the OP.
Everyone seems to end up discussing some new async-useful algorithms or datastructure that will "save the day", but in reality, until you start encoding application logic processes into decoupled, testable containers, you're always going to fight some complexity. This really has nothing to do with async, the principles of encapsulation and coupling are absolutely well discussed and documented, and merely apply even more vehemently to the async space. The unfortunate fact is that many of the users of these libraries do not factor code in this manner, and as such this discussion comes up again and again.
I honestly don't know of any good open source examples of complex async applications in either language (ruby or javascript) that are well structured. I can point you time and time and time again at libraries that are poorly constructed based on the "trivia" examples that "don't require" any structure and so just use a single object/scope and some closures to achieve a minimal use case.
There are many possible reasons for this lack of good examples. The reason I haven't written one is because it still takes some care, mostly in architecture, and no one will pay me to write such open source. There probably are some good examples in C, based on libev, libevent, glibs loop, etc, etc. I'm not intimately familiar enough with any example code bases to be able to call them out off the top of my head.
- samstokes 16y agowrite state machines inside objects to maintain state and process flow, and advising them to wrap callbacks into message sends to these process containers Any chance you could give an example of this refactoring / change of perspective (or link to a blog post, etc)? I can almost imagine what you mean, but it sounds like useful enough advice that I'd really like to grok it, and a concrete example would help a lot. I'm currently working on another approach to reduce the complexity and error-proneness of evented programming. I'm working on a combinator library to abstract and automate the more common patterns of wiring up callbacks and propagating exceptions. Have you seen any success (or pitfalls) from this kind of approach?
- moe 16y agoI honestly don't know of any good open source examples of complex async applications in either language (ruby or javascript) that are well structured. So, at first you claim there is clean way to do it, but then you admit nobody is doing it the clean way? That sounds a bit strange, doesn't it? I think the reality is that there simply is no pattern to escape callback-hell in complex evented applications. Or why else would everybody still be writing the same spaghetti-code with the logic scattered over at least two callbacks (success/errBack) per unit of work? I'd go as far and claim the spaghetti-pattern is inherent to evented programming, unless you wrap it all up in something sane like co-routines.
- mtoledo 16y agoI think what raggi said is that there are no good _open source_ _complex_ async _apps_, mostly because when people are writing open source they tend to write libs, not apps, or end up not working anymore at the problem before it gets really complex. I've worked on a commercial, complex, async codebase with raggi and have to agree that there is a way other than callback-hell, even for complex evented applications. In my personal opinion, even more so on ruby than javascript, but I don't want to get to that really. edit: changed asterisks to underscores because I didn't know they'd be italicized
- moe 16y ago