21 Nested Callbacks
blog.michellebu.com
blog.michellebu.com
I'm simultaneously reminded of two different quotes:
Let's argue about whether Haskell or Clojure is better while somebody else ships products using PHP and duct tape. --@agentdero [0]
And the other:
<dm> I discovered that you'd never get an answer to a problem from Linux Gurus by asking. You have to troll in order for someone to help you with a Linux problem.
-- Bash.org [1]
You should always try to do SOMETHING over being frozen in indecision. Additionally, we really should do a better job of explaining things to people, so they don't have to stoop to trolling for answers :)
I'm from Middle America. In Middle America, when you ask a farmer what he feeds his pigs, he tells you what he feeds his pigs, what he doesn't feed his pigs, why he feeds his pigs what he feeds his pigs, how he feeds his pigs, and what sunscreen he applies to their skin.
So it was very weird to me that a lot of programmers didn't like to share their knowledge of programming (except, it seems, when they are trying to impress other programmers).
For programmers, everyone is trying constantly to braindump to everyone else; that's half of what the blog posts on HN consist of. And everyone wants their braindumps analyzed, and, more importantly, debugged. "I'm feeding my pigs horse meat--did I make the right decision?"
When you're exposed to it so often, it's hard not to get tired of telling people about the benefits of grain over horse meat.
The person listening learns something new, and is able to see something beautiful in the way that someone else sees it. Additionally, the person who's doing the explaining gains the experience of trying to relate their idea to another person, an exercise that often expands the explainers understanding of the idea.
I really wish more people explained what they love and find interesting!
But it's a very different kind of explanation than "here are all the building blocks you need to put together in order to understand how wrong the way you're currently doing things is." The second kind is pretty much what all "innocent programming questions" require in response.
I exhort everyone to strike up these kinds of conversions especially with strangers as often as possible - I guarantee you will learn something interesting :) Ever since I got the hang of it, it has really enriched my life.
Done properly, it's fun, though you do need some form of ongoing trust - it's not something you should do to someone piping up for the first time on IRC.
Feeding pigs is the tip of the iceberg. If you want to see some sparks fly, just sit down at the local cafe and talk about the comparative yield of soybeans and corn, and why anyone growing X percentage this year with the weather pattern is just plain nuts.
It's not quite the same as the family-farm days (most are now corporate owned), but those were the first debug sessions I listened in on as my grandfather held court among his colleagues.
I think I see what might've been going on now, though; I don't think it was because the question "What's CSS?" (or similar) is too dumb, and I especially don't think that it's because no one wanted to help you (or thought you're incompetent).
Rather, it's because when you're starting to program, you don't _know_ that you can Google the solutions to so many problems so easily, so you ask the people around you. It's perfectly sensible. So, one of the things that programmers try to teach other beginning programmers early is that Google makes a lot of information easy to access, and so they try to help you by telling you that you can Google before asking.
It's not that they don't want to answer, or that they feel you're hopeless -- they're just trying to teach you how to fish, instead of giving you a fish. :) I'm sure if you ask the exact same question _after_ you have failed to find the answer after a 2-minute search on Google, you will not be turned down for the answer -- programmers generally love to help each other figure out how to do stuff. And one of these things they like teaching is that you can find answers to a lot of questions online!
That's not too hard to explain. Some programmers see themselves as part of a clique. Their code and ways are what keeps them superior, experts in the field that they work in. The sunscreen that coats their javascript perhaps took them a hard couple hours of debugging to discover, and many programmers are the type of people who feel and rationalize "If it took me this long, this newb should go through the same process".
Of course, there are many exceptions- all the online communities, forums, etc. But there's always some part that does work as I described. Hell, even I get annoyed sometimes and tell someone who's starting out "go google why you don't want a GOTO statement in code"...
Any programmer who thinks like that is a poser.
I'm not sure why this always happens just after the 1000 mark.
Artificially reducing some ill-considered "competition"?
blog.michellebu.com/assets/divart.html
I think the farmer can reasonably expect a layman to understand most of the things related to feeding pigs.
I, on the other hand, have no expectation that a layman would understand pointers, lambdas or any of the other lovely complicated things that even answering simple questions COULD entail if we went into details or expanded around the question.
[EDIT: Apologies it this comes off as arrogant or elitist or something, not intended.]
Of course, the information might also be a bit biased: everyone has their own preferences and opinions, and usually present them fairly strongly. Some people hedge about other options half-heartedly, but I doubt anyone would give you an even spiel on more than a couple of different options. Which is entirely natural: chances are, nobody has much experience with more than a couple of different options.
This might also vary a bit by community. I haven't spent much time recently talking to web developers. But the general programming languages/functional programming community is certainly fairly talkative.
You wanted to do a thing. You made the computer do that thing. Programmer.
It's not about proving you're the smartest person before you even touch a keyboard. It's about being persistent, doing experiments, and always learning.
And I expect that your friend has forgotten the sort of things he did when he started.
From my reading, it appeared as a complement as in "no beginner programmer would actually go through the pains of finishing it, and finishing it on your own is a feat."
Young farmer: I got some pigs, but I don't know what to feed them. What do you feed your pigs?
Old farmer: I had some pigs once, I fed them one of my cows that had died of consumption.
Young farmer: Really?
Old farmer: Yup.
<2 weeks later>
Young farmer: One of my cows died, so I fed it to my pigs. They all died. Your pigs really thrived on meat of a diseased cow?
Old farmer: Nope, my pigs died.
In fact, I think that's probably a part of the reason why some programmers don't have patience for beginners with a lot of questions. It's because beginners actually have Google and StackOverflow these days, so it might seem like laziness to someone who had to learn using books and man pages. It's not that they don't like to share their knowledge, it's that they think the answer is already there if you'd bothered to look. I'm not saying that they're right to have that attitude, by the way. I'm just trying to present things from their perspective.
Sure, you can spend an afternoon or so to write and debug those 20 nested callbacks, but surely, it is more fun and thus better to spend a couple of _days_ thinking of the problem, googling for solutions, getting distracted by some nice algorithm, attempting to apply that in a totally distinct, perfectly working part of your codebase, renaming a couple of functions, etc., and finally replace that nested thing with some carefully placed '.each' or '.map' (after gauging which solution looks best, aesthetically)
Yes, there may be commercial pressure to ship a product, but in the hearts of many programmers, the journey is the reward.
Granted, Kurt von Hammerstein-Equord was a nazi fuck and was talking about leadership, but I have found the best programmers are extremely lazy, however they have a constant drive to figure things out, take them apart, and put them back together again. They also generally have a need in the same vein of "write programs so they don't have to do the work of copy pasting 100 times in the first place" even if they spend 4 hours figuring out to do that.
"Granted, Kurt von Hammerstein-Equord was a nazi fuck"
Nope, you didn't.
"He is famous for being an ardent opponent of Hitler and the Nazi regime."
Nope, you didn't.
"Slow down when you get to the old Willoughby place, you'll know it by the brick shed they built in back, because the statey likes to sit behind the hill and catch speeders, and after five minutes, you'll want to go left..."
I grew up on the extreme western frontier of Flyoveria, in Eastern Washington State. We had a culture of the same sort of accreted experience that results in journeymen in their various careers. There's a reason a lot of phrases such as "college boy," "doesn't know sh8t from Shinola," etc. tend to be more common, and it's not just because they're "folksy." On the other hand, they really want to save people from themselves if they're willing to learn, and they'll tell you all you need to start farming pigs. You'd better be ready to help him with his computers, though, even if he's running his farm on a Kaypro II.
In programming, there's not as much of a long-term investment in the apprentice-journeyman-master guild-style system, although you can find pockets here and there. I have lamented it and pondered the reasons for its erosion over the past 20 years, but I can't say with real authority why we don't have it any longer, other than an expected lack of tenure at any organization.
It's not like big law or finance, where your first firm is there to grind you out of the business before your second firm decides if you're up or out.
The fact that she went through with it and got it to work, despite how it ended up looking, is commendable.
And I really like the result. Anyway, this article was neat and put a smile on my face.
This is one of my Jedi-level secrets of technical management.
I am quick to say I have a huge ego, because anyone who knew me would fight to say it first. The fact that I know what I know and have a good feel for where I'm weak lends me confidence in those situations where I'm mostly out of my depth.
I've managed ultra-introverted developers for about makesmesoundold years. Numerous are the times I've asked a question and gotten no answer. "How would we go about accomplishing x?" "How long would it take us to do y?" "What letter comes after z?"
Crickets
Throw a proposal just plausible enough that people think you're serious, but so "insane" that it almost defies logic ("what if we put, say, hmm...log base two of 2097152 is 21...jQuery callbacks in an HTML file full of id'd divs..."), then it's as if a tiny rock starts rolling down a hill. First one person offers a criticism, and then we get more people engaged, throwing out the alternatives that they would have suggested in the first place.
Eventually, they recognize the game, and then it's a fun brainstorming activity. Or you fire three as a message to the others.
This got my upvote. ;-)
Amusingly, I've noticed the same thing: I do claim that a surprising amount of things are simple. And you know why? Because they are. A whole bunch of things (most recently F-algebras and F-coalgebras) really are simple: you start with a very simple concept (say sets and functions) and build up to them, taking very simple steps along the way. Maybe you have to bring in a couple of other concepts that are similarly simple.
EDIT: I should have made this clearer: I say something is simple before trying to explain it rather than instead of. I mainly do it to avoid scaring people without reason, and everyone gets far too scared of words like "F-coalgebra" or even "monoid".
Every single step along the way? Virtually trivial. But put them together and you get something genuinely difficult to follow.
It turns out that enough trivial steps all building upon each other becomes difficult to follow for anyone. Yet, once you've finally understood it, you can't see why it was difficult any more: after all, all the components are so simple, and it all makes sense! (Now.)
I realized this in a pretty direct way: I was trying to explain the aforementioned algebras to some of the smartest people I know--people with much more mathematical experience and aptitude than me--and they all found it a bit hard to follow. Not because they couldn't follow any particular step, but because putting it all together in your head is difficult.
So really, the ultimate conclusion is: just because something is simple does not mean it is easy. Having some trouble with simple concepts like this is not an issue at all; everybody does. But that doesn't mean they aren't simple!
Another, more surprising, conclusion is just how shallow the stack of concepts has to be to cause people trouble. It's not like there are hundreds of parts in these definitions: there are maybe 10. (Say: set, function, algebra, identity, category, morphism, functor, dual.) And yet this is more than enough to confuse.
My brother and I learned to program in BASIC on an Apple IIe when we were kids. At the time, we were also into making little movies with our family's VHS camcorder. You could draw graphics in BASIC, so we thought it would be radical to write a program that would draw a cool logo animation for our movies.
We got a big sheet of graph paper and hand-drew the intended pixel art for our logo. Then started writing code to draw it one line at a time. We put a delay between each line so that it would do an animated wipe. We knew how to pause by doing a busy loop:
10 FOR I = 1 to 100
20 NEXT I
What we didn't know was how to define reusable procedures (GOSUB). So between each of the hundred lines of pixel art, I typed in that loop. And I mean that literally: this was a line editor. No copy and paste. I wrote it out each time.Now I just lament having the much free time and focus to be able to do that...
Would you have been better off 'doing things right' from day one, versus experimenting and muddling through?
Nobody hits my brother but me.
Programmers are persistently frustrated in our tools-- when you can see how things work, you start to see just how broken it all is. Things that should be easy are hard, things that should be hard are nearly impossible. And for every thing gotten right, there's something a little subtler that's completely and opaquely wrong, wasting days of your life. We hate our tools, and we love to complain about them.
But if you complain about our tools... Sorry, who are you? This is basic stuff.
In other professions, blaming your tools is essentially a "There's nothing I can do about it -- the tools just suck."
In programming, we can go "These tools suck, but I can fix them". Of course, then you never accomplish what you initially set out to...
I see this attitude as being like a lot of hot rod restoration people I've known: they like working on cars, but seemingly not necessarily driving. They don't ever want to be done, so they keep finding broken stuff, and the end result is that their "tool" is always broken. The Lego castle can always use another brick, you know? When do they ever drive, and if they do, are they happy when they do it or are they complaining inside the entire time? "Engine feels a little rough" is "my computer seems slow" is "that could really be automated." To me it's all just stuff that is other-than-coding. Pretty much just give me a fuzzy-filefinder with `screen` and I'm good, I gave up tinkering quite a while back.
From OP: "Programmers are persistently frustrated in our tools-- when you can see how things work, you start to see just how broken it all is. Things that should be easy are hard, things that should be hard are nearly impossible. And for every thing gotten right, there's something a little subtler that's completely and opaquely wrong, wasting days of your life. We hate our tools, and we love to complain about them."
> We're in a funny profession where we're both the people making and using the tools.
I don't mean that every single programmer is making and using the tools, just that the skillset for making and using the tools is pretty similar.
Note that I said "we can go <bla>". I'm not really advocating stopping what you're doing to tinker with your tools. It's just that it's often a tantalising possibility which people in other professions are less tempted by.
As you say, though, if you want to get anything done, you have to resist the temptation.
Sorry world. It's getting better. But slowly.
For a while, I was even hesitant to simply show some of my projects to other developers I looked up to..I figured the code was so bad, and the project so trivial, that why bother?
Reading sites like HN, you read about these tremendously talented people.... doing exits, building absurdly cool projects that you think you'll never be able to build... and it's easy to benchmark yourself against that sort of ideal and think that your stuff isn't cool enough. When I finally was confident enough to share some projects with a few people I respected, I was blown away by how much I learned just listening to their feedback.
Even if you think you're code sucks, you'll improve rapidly by learning WHY it sucks, and using that in new projects.
To my genuine amazement, the company I worked for immediately after leaving college is still using a program I wrote for them seven years after I wrote it. When I left, they said that every company operation was going to be covered by SAP- weird how that didn't work out...
But still, it was written in VB.NET (!) and was a horrible, horrible mess. I would love to take a look at that code now, but I'm afraid that if I contact them they'll hold me responsible for updating it.
function animate_opacity_to(opacity) {
var elems = $('[id^=row]').get();
(function x(){
var el;
if(el = elems.pop())
$(el).animate({opacity:opacity},100,x);
})();
} function animate_opacity_to(opacity) {
$('[id^=row]').forEach(function(el) {
$(el).animate({opacity: opacity}, {duration: 100, queue: true});
});
}
(haven't tested this but I think it should work.) In general, I've found that using a queue or queue-like structure can often help alleviate the dreaded "callback waterfall". Instead of saying "do this, then when you're done, do this, then when you're done, do this", you're saying "here are a list of the things I want done, do them in order and don't start the next thing in the list before the previous one is done". If you have some things in the queue that can be run simultaneously, you can combine them with a Deferred (see http://api.jquery.com/jQuery.Deferred/ )In any case, great article - I definitely remember many similar scenarios that came up while I was learning to code. Sometimes you just gotta go with the crappy implementation you know will work rather than the efficient implementation that is beyond your current understanding :)
What will work is adding `delay` e.g.
$(el).delay(i*100).animate(...
But that causes other problems because frantically clicking will cause the animations to get queued. Setting `queue` to false, breaks .delay(). $('[id^=row]').toArray().reduce(function(l,r){
return l.pipe(function(){
return $(r).animate({opacity:opacity}, 100);
});
}, $.Deferred().resolve());
Obviously, you can put any selector in there and you'll get them animate in order. Hence, allowing you to play with many combinations, once you spend the time to write this once. I agree with the OP about getting something done is always better than nothing. Yet, the responses that s/he got from programmer friends is not an issue of technical pragmatism, but one of collaboration culture. Unfortunately colleges are like that. Things are different in more professional settings. $('[id^=row]').toArray().reduce(function(l,r){
return l.pipe(function(){
return $(r).animate({opacity:opacity}, 100);
});
}, $.Deferred().resolve());
but without .reduce() you have: var pipeline = $.Deferred().resolve();
$('[id^=row]').each(function(index, row) {
pipeline = pipeline.pipe(function() {
return $(row).animate({opacity:opacity}, 100);
});
});
(untested) which is, to my eyes at least, more readable. Just because you can do anything with .reduce() that you can do with a for loop doesn't mean you should.In the reduce case, the deferred is in the scope of the function as a named argument; which is the main advantage of using deferred in this case. In the .each loop, deferred is a variable in the outer scope. Even though it looks like it will work (need to try), I wouldn't consider it the safer and more readable solution.
I think reduce() is awesome for associative operations and in general reasonable in point-free style. But I don't think its use in this case improves readability.
var pipeline = $.Deferred().resolve();
$('[id^=row]').toArray().reduce(function(l,r){
return l.pipe(function(){
return $(r).animate({opacity:opacity}, 100);
});
}, pipeline);
But, more than avoiding mutations, thinking of the loop as a .reduce made it easier for me to write the code. The reduce has a semantic goal of computing one value out of the array, besides explicitly handling intermediate results, e.g. in this case, you can think about the .reduce as computation of a single deferred that will fire when everything completes, whereas you can get to the same effect with the .each loop by using the pipeline variable. var alldone = $('[id^=row]').toArray().reduce(function(l,r){
return l.pipe(function(){
return $(r).animate({opacity:opacity}, 100);
});
}, $.Deferred().resolve());
The conceptual boundary between .each and .reduce is blurred due to the two-phase nature of this code, i.e. the outer function runs as soon as the execution hits the statement and traverses all the elements, and the inner function runs as the deferred chain fires and consumes the deferreds. .reduce allowed me to think both the inner and outer functions to run as a reduction; even though the outer is really a loop.Interesting thing about code reviews: 10% of the code generates 90% of the discussion.
I was so eager to get the graphical part out there that I didn't think about the problems of modeling, or having multiple objects on the screen at once. The whole thing was a single-file, thousand-line, hard-coded mess. And I still think it was awesome.
The important thing is to remember that there aren't (m)any super geniuses for which this stuff spews out first try. It's just that some people had the benefit of working through their ridiculously terrible code at the age of 8, writing BASIC, or whatever. And while they may have to learn jQuery the same as you did, they have a massive class of "intuitive" knowledge, which is really just experience, to help them through most of it.
"I gathered from these exchanges that programmers have a perpetual competition to see who can claim the most things as 'simple.'"
It just goes to show that if you really have a passion for something and you really work hard at it, you can become awesome at it (or at least good enough to know you can be awesome without that much work) in no time. I find that this usually holds for most things in life, but it lends itself to web design especially.
And judging by her github profile, she's a good programmer by any reasonable definition.
That said, anyone that learns from their mistakes will become great.
Impressive is a slight understatement.
Just goes to show that talent is as much inate as it is countless hours bashing against the wall. I had a lot of patience when I was 9.
My particular favourite is the Lamina library in clojure which takes the event-driven approach https://github.com/ztellman/lamina/wiki/Introduction
http://msdn.microsoft.com/en-us/library/vstudio/hh156513.asp...
Just a rebuttal to one point that irked me.
That helped a lot, and I don't resent them for that type of help at all. I'm sorry if it came across that way in the writing.
This is very true. Especially early on, while learning basic concepts, I found it very difficult to Google things because I did not know the terms or concepts involved. When I was attempting to self-teach my first programming language (Python), I could not understand the difference between parameters and arguments - but I didn't know that that was how to characterize my problem either. I just thought "why doesn't 'x' mean what I said it means over there?"
And it's always funny to go back to our beginnings and see the difference in code and level after only some years :)
It isn't very uncommon to have code that would cause most to projectile-vomit in products that are massively successful, reliable and, yes, very profitable.
For design, there's always Craigslist.
You have entire and complex projects on github available for free , so no Programming is not hard , it takes time to become a good programmer yes but like everything else in life. You want to try something hard ? try to be a doctor instead.