<br><div class="gmail_quote">On Mon, Aug 3, 2009 at 6:00 PM, Edward Z. Yang <span dir="ltr">&lt;<a href="mailto:ezyang@mit.edu">ezyang@mit.edu</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I have updated my draft here:<br>
<div class="im"><br>
    <a href="http://ezyang.com/twisted/defer2.html" target="_blank">http://ezyang.com/twisted/defer2.html</a><br>
</div></blockquote><div><br>Thanks.  Looks like it&#39;s improving.  I&#39;ve got more points to critique now, but that&#39;s only because there&#39;s more meat to the tutorial now :).<br><ol><li>The coding standard in this document is PEP8, not the Twisted coding standard.  Have a look here: <a href="http://twistedmatrix.com/trac/browser/trunk/doc/core/development/policy/coding-standard.xhtml?format=raw">http://twistedmatrix.com/trac/browser/trunk/doc/core/development/policy/coding-standard.xhtml?format=raw</a></li>
<li>&quot;Callbacks are the lingua franca of asynchronous programming&quot; strikes me as an odd turn of phrase, especially one to open the document with.</li><li>&quot;This document addresses ... Deferred.  It...&quot; - &quot;It&quot; has an ambiguous antecedent.  Are you talking about the document or the Deferred class?  Of course it becomes obvious, but it should be phrased so you don&#39;t need to.</li>
<li>It&#39;s far from obvious what &quot;nonblocking_call&quot; is supposed to be, given that its definition is &quot;pass&quot;.  On my first skim through I thought it was a callback, then had to stop, go back and read again when I realized that didn&#39;t make sense.  Brevity is good in examples, but this is too brief.</li>
<ol><li>&quot;input&quot; is a builtin function.  You might want to avoid using it for a parameter name.<br></li></ol><li>&quot;You might be tempted to define it like this&quot;: you&#39;re switching back and forth from second to third person; at first referring to the reader, then an anonymous different programmer.  It might be useful to give these roles different names; &quot;Alice and Bob&quot; are popular.  <br>
</li><li>If you must use a third-person pronoun (as you do the one time you refer to the API&#39;s anonymous user); you should stick to a gender-neutral one wherever possible, unless of course you&#39;re referring to a specific character.<br>
</li><li>&quot;The Deferred doesn&#39;t do anything that you couldn&#39;t have done with the two callback parameters.&quot;  This isn&#39;t strictly true; chaining callbacks, and dealing with errors that arise in different layers of an asynchronous callback chain, aren&#39;t strictly possible without some additional mechanism.</li>
<li>Deferred is mentioned as an API link, Failure isn&#39;t.</li><li>Your explanations of the examples seem backwards.  &quot;At its very simplest, Deferred has a single callback attached to it&quot;.  I think you should be explaining the problem being solved by a single callback, since the synchronous example isn&#39;t addressed.  The synchronous example obviously doesn&#39;t have a single callback attached to it :).  In other words, document &quot;here&#39;s what you might want to do, here&#39;s how you can do it&quot; rather than &quot;here&#39;s a thing you can do!  by the way, you might want to do it because...&quot;.  You&#39;ve addressed the general why-you-want-to-do-it in the section above, but it would be helpful to do it in the small for each specific example.</li>
<li>The DeferredList docs seem wonky in several ways.</li><ol><li>The opening is hard to follow. <br><blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote">
We are now ready to consider our original problem</blockquote><div>what original problem?<br><blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote">
<span></span><a name="auto9">a Deferred that
would only fire</a></blockquote><div>&quot;fire&quot;?  what does &quot;fire&quot; mean?  The term hasn&#39;t yet been introduced.<br></div><blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote">
<a name="auto9"> after some other number of Deferreds fired</a> </blockquote><div>Yeah, I&#39;m still not sure what you&#39;re referring to.  Why would I want to do this, again?<br></div></div></li><li>Users really shouldn&#39;t be subclassing Deferred themselves, so it&#39;s bad to have an example that does that.  Especially one which .  The fact that this is what DeferredList is is an implementation detail, and an ugly one at that.  Try talking about gatherResults instead, and implementing a function which does the same thing without a subclass.  Or, perhaps, a class of your own which just delegates to Deferred for Deferred behavior, rather than inheriting it.<br>
</li><li>Users <i>definitely</i> shouldn&#39;t be subclassing Deferred without upcalling to its __init__.  I haven&#39;t tested them, but I&#39;m pretty sure these examples will just blow up with tracebacks.<br></li><li>The examples are never invoked.  It&#39;s semi-obvious how to use them, but semi-obvious things are often invoked semi-correctly.  Better to have examples with can be run, or at least ones with a 0-argument entry point named something like &#39;start&#39;.</li>
<li>&quot;Consider the following interaction of two Deferreds:&quot;.  You&#39;re setting this up as if it&#39;s going to be very formal, but then your language is sloppy; you don&#39;t name the different deferreds.  One of them is &quot;one deferred&quot;, the other is &quot;a <span style="font-family: courier new,monospace;">Deferred</span>&quot;.  You don&#39;t describe them independently, the relationship is implicit in the description.  Given that you&#39;re describing a fairly complex constellation of objects with which the user isn&#39;t necessarily familiar yet, you should be clearly labeling the Deferreds in question in the code sample with variable names (something as simple as &quot;a&quot; and &quot;b&quot; would probably do fine) and then consistently using those names to refer to them in the prose as well, so it&#39;s easy for the reader to follow exactly which thing you&#39;re talking about.  A big problem with technical documentation, <i>especially</i> documentation of Deferreds, is that it&#39;s very easy for a reader to start confusing which thing is which.  Once again, it would be good to set up some kind of concrete problem first: <i>why</i> are we waiting on multiple Deferreds?<br>
</li></ol><li>&quot;Fluent Interface&quot;?  This is more new terminology — terminology that I am not familiar with, I might add — that isn&#39;t defined anywhere in the document.  I think it&#39;s more of an appendix than something important to the main narrative; composing Deferreds, returning a Deferred from another Deferred, firing a Deferred from another callback, etc, should be covered first.<br>
</li><ol><li>&quot;Batons&quot; looks like it&#39;s going to be more fancy ad-hoc terminology - I would recommend keeping the language simpler and consistent with other Twisted documentation :).</li></ol><li>Still a lot of enumerated lists.  Obviously a bad habit to which I am prone ;-), but when one uses an enumerated list, there should either be in an expectation that the numbers will be useful.  Either, as in this document review, or code reviews, where the numbers can be used to refer to points in subsequent discussion, or there&#39;s a clear separation of steps.  It&#39;s not really clear what the &quot;two possible scenarios&quot; lists are enumerations <i>of</i>.  Are they different things that can happen?</li>
<li>You should try eliminating the word &quot;consider&quot; from the document.  You seem to have the rhetorical habit, which I&#39;ve seen from other people (myself included), of having a sentence which is missing a clear subject/verb/object relationship, and working around it by saying &quot;consider&quot; or &quot;let&#39;s say&quot;.  For example, you want to communicate that there&#39;s a Deferred somewhere with some callbacks.  You can&#39;t just say &quot;A Deferred with some callbacks.&quot;, so you say &quot;Consider: a Deferred with some callbacks&quot;, and now the sentence <i>seems</i> complete, but it doesn&#39;t really communicate a full thought.<br>
</li></ol>Okay, I think that&#39;s enough feedback for now.  I&#39;ll have to do more with your next round of edits, or my feedback is going to be longer than the document itself :).<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
* Why asynchronous?<br>
    - Define synchronous and asynchronous<br>
    - Multiplexing IO<br>
    - Introduce a simple reactor based on select()<br>
* Why callbacks?</blockquote><div><br>You might want to start with this one, since callbacks are even more generally useful than asynchronous programming.  Your suggestion of a parser example makes this clear: even if you&#39;re parsing synchronously, you&#39;ll still probably have callbacks for different parse rule matches.<br>
 <br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">   - Asynchronous interaction to synchronous interaction<br>
    - Delocalized execution (the parser example)<br>
    - High level functions in Python review<br>
<br>
Quite frankly, I&#39;m stumped on &quot;defining synchronous and asynchronous.&quot;</blockquote><div><br>I&#39;d start with the words themselves.  synchronous means &quot;at the same time&quot;.  This refers to the timing of the function call and its effects.  In a synchronous program, if I say &quot;read()&quot;, then at that same time that &quot;read()&quot; is called, the reading happens and the data is returned.  But, in an <i><b>a</b></i>synchronous (&quot;not at the same time&quot;) program, &quot;read()&quot; is called, but its effects happen later.<br>
<br>This can obviously be fleshed out quite a bit, but I think that core concept is what&#39;s important to communicate.<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Asynchronous had always made sense to me, coming from JavaScript, since<br>
it was &quot;you click this button and something should happen!&quot;  But that<br>
is a very different use-case of asynchronous programming than Twisted is.</blockquote><div><br>Your experience with JavaScript — or at least, with GUI programming, since JavaScript itself is terrible — might actually be a good way to explain the problem here.  One example I like to use to explain why sometimes you just can&#39;t block is this:<br>
<br>    button1 = Button()<br>    button2 = Button()<br>    # I need to wait for the user to click on this button<br>    button1.waitForClick()<br>    # okay now they&#39;ve clicked it.<br>    message(&quot;Hooray you clicked button 1&quot;)<br>
    button2.waitForClick()<br>    # oh dang, but what if they want to click button 2 first!?!<br><br>although you can probably devise a more lucid variant of that :).<br><br>One of these days I really want to write a combined Twisted / GTK tutorial that shows how to ask questions in dialog boxes without blocking and sub-main-loops and other nasty tricks that GTK programs often get up to in order to have a question-and-answer UI.  Unfortunately, although these examples do serve as easy-to-identify for learning Twisted programmers, it&#39;s not always immediately clear how this corresponds to networking data, and the extra complexity of GUI libraries makes it more difficult to run the examples.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">And Glyph raised some very salient concerns about what we were trying to teach people.  I just don&#39;t know what direction people are coming from.<br>

</blockquote><div><br>I think the best assumption of background for such an introductory tutorial is to assume that the user doesn&#39;t really understand what problem Deferreds solve, and has thus never done any substantial work in an asynchronous environment.  More experienced users will skim some parts, but that&#39;s fine: more experienced users are easily able to figure out what Deferreds are even with just the current documentation :).<br>
<br>We shouldn&#39;t treat this as a Python tutorial, but it should at least touch briefly on callable objects and nested variables.<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
As such, the document now is targeted to &quot;people who know the basics<br>
of asynchronous programming and grok callbacks&quot;, and I&#39;ve incorporated<br>
Itamar&#39;s excellent suggesting of comparing explicit callback parameters<br>
and the Deferred object, which I hope dispells the notion of Deferred<br>
being magical fairly well (my assertion is Deferred is merely an<br>
abstraction over said callback parameters.)  I&#39;ve also fully fleshed<br>
out the Deferreds reference; any omissions are my fault.<br>
</blockquote><div><br>Again, I think this might be assuming a bit too much.  At the very least, you should find a very, very good tutorial on callbacks and higher-order functions in Python to point people to as a dependency, so that users who <i>don&#39;t</i> have that experience can go read about it somewhere else.  (Actually, every dependency of every document <i>really</i> ought to have hyperlinks to other resources that teach that dependency, so that a user who doesn&#39;t know python but needs to dive into a Twisted codebase will be put on their way quickly.)<br>
<br>Even people who have some Python experience, but use callbacks rarely, will often discover there are things they don&#39;t know when they start programming with Twisted and nesting 5 or 6 callbacks in a function.  For example, many people don&#39;t know all the fiddly rules of scope nesting.  Take a poll of some potential targets for this intro documentation and ask them if they can explain why this produces an error:<br>
<br>    def f(x=1):<br>        def t():<br>            if x &gt; 3:<br>                x = 2<br>            else:<br>                return x<br>        return t<br><br>... but adding &#39;x=x&#39; to the parameter list of &#39;t&#39; makes it work (although not like they would expect if they manipulated &#39;x&#39; in f).<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">The plan next is to discuss composing deferreds (which will also<br>
touch on when you should and how to create your own deferreds, as<br>
well as deferredlist) and the convenience primitives.<br></blockquote></div><br>I think you need to start talking about creating your own Deferreds, at least implicitly, very early on in the document.  For example, rather than having &quot;nonblocking_call&quot; be a dummy function, have it maintain a list of yet-to-complete calls, like this:<br>
<br>    pending = []<br>    def process(data):<br>        return &quot;Processed: &lt;&quot; + data + &quot;&gt;&quot;<br>    def nonblockingCall(data, whenSucceeded, whenFailed):<br>        pending.append((data, whenSucceeded, whenFailed))<br>
    def completeOneCall(succeeded=True):<br>        data, whenSucceeded, whenFailed = pending.pop(0)<br>        if succeeded:<br>            whenSucceeded(process(data))<br>        else:<br>            whenFailed(RuntimeError(&quot;It failed, for some reason.&quot;))<br>
<br>then (A) you can demonstrate how the callbacks actually get called in a tiny little system that the reader can play around with and get comfortable in before understanding Deferred, and (B) you can illustrate the same example again with some Deferred logic involved.<br>
<br><br>