Posts about twistedhttps://mithrandi.net/categories/twisted.atom2018-05-19T08:14:07ZmithrandiNikolaFlow control with Deferreds, by examplehttps://mithrandi.net/blog/2011/06/flow-control-with-deferreds-by-example/2011-06-26T11:42:46Z2011-06-26T11:42:46Zmithrandi<div><p>[NOTE: If you are reading this post in an RSS reader, the formatting on the
code examples may not be optimal; please read this in a web browser with
JavaScript enabled for the optimal viewing experience]</p>
<div class="section" id="introduction">
<h2>Introduction</h2>
<p>I often find myself helping newer Twisted users come to grips with arranging
their flow control when they first start writing code that uses Deferreds.
While the <a class="reference external" href="http://twistedmatrix.com/documents/current/core/howto/defer.html">Deferred Reference</a> does a reasonable job of covering all of the
details, it is often difficult to make the intuitive leap from the synchronous
patterns one is used to, to their asynchronous equivalents. To that end, I
often find that comparing sync and async versions is illustrative; there are
some examples of this nature in the Deferred Reference, but some patterns are
missing, and I've never actually put all of the examples down in one place, so
I thought I'd do that in my blog post. Without any further ado, here they are:</p>
<p>EDIT: Added composition example</p>
<div class="section" id="call-a-function-and-use-the-result">
<h3>Call a function, and use the result</h3>
<pre class="code python"><a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-2"></a><span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-3"></a><span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-4"></a>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-5"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-6"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-7"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-catching-a-particular-exception">
<h3>Call a function and use the result, catching a particular exception</h3>
<pre class="code python"><a name="rest_code_0165eddc75814d19960d16eea78070e9-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-4"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-5"></a><span class="k">except</span> <span class="n">SomeException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-6"></a> <span class="n">handleError</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-7"></a>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-9"></a><span class="k">def</span> <span class="nf">_eb</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-10"></a> <span class="n">f</span><span class="o">.</span><span class="n">trap</span><span class="p">(</span><span class="n">SomeException</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-11"></a> <span class="n">handleError</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-12"></a>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-13"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-14"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-15"></a><span class="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">_eb</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-catching-any-exception">
<h3>Call a function and use the result, catching any exception</h3>
<pre class="code python"><a name="rest_code_8b58173953434680ba0eb12d0ab76452-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-4"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-5"></a><span class="k">except</span><span class="p">:</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-6"></a> <span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">()</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-7"></a>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-9"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-10"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-11"></a><span class="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-catching-exceptions-raised-by-that-function">
<h3>Call a function and use the result, catching exceptions raised by that function</h3>
<pre class="code python"><a name="rest_code_1861872373f44de5afc681f330d29c6f-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-4"></a><span class="k">except</span><span class="p">:</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-5"></a> <span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">()</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-6"></a><span class="k">else</span><span class="p">:</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-7"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-8"></a>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-9"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-10"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-11"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallbacks</span><span class="p">(</span><span class="n">doSomething</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-recovering-from-a-particular-exception-raised-by-the-function">
<h3>Call a function and use the result, recovering from a particular exception raised by the function</h3>
<pre class="code python"><a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-4"></a><span class="k">except</span> <span class="n">SomeException</span><span class="p">:</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-5"></a> <span class="n">result</span> <span class="o">=</span> <span class="mi">42</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-6"></a><span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-7"></a>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-9"></a><span class="k">def</span> <span class="nf">_eb</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-10"></a> <span class="n">f</span><span class="o">.</span><span class="n">trap</span><span class="p">(</span><span class="n">SomeException</span><span class="p">)</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-11"></a> <span class="k">return</span> <span class="mi">42</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-12"></a>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-13"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-14"></a><span class="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">_eb</span><span class="p">)</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-15"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-performing-cleanup-if-an-exception-occurs">
<h3>Call a function and use the result, performing cleanup if an exception occurs</h3>
<pre class="code python"><a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-4"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-5"></a><span class="k">finally</span><span class="p">:</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-6"></a> <span class="n">cleanStuffUp</span><span class="p">()</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-7"></a>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-9"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-10"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-11"></a><span class="n">d</span><span class="o">.</span><span class="n">addBoth</span><span class="p">(</span><span class="k">lambda</span> <span class="n">ignored</span><span class="p">:</span> <span class="n">cleanStuffUp</span><span class="p">())</span>
</pre></div>
<div class="section" id="compose-several-functions">
<h3>Compose several functions</h3>
<pre class="code python"><a name="rest_code_7982cdb9875f49afbb5a669100280b60-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-2"></a><span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-3"></a><span class="n">result2</span> <span class="o">=</span> <span class="n">doStuff</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-4"></a><span class="n">result3</span> <span class="o">=</span> <span class="n">doMoreStuff</span><span class="p">(</span><span class="n">result2</span><span class="p">)</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-5"></a>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-6"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-7"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-8"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doStuff</span><span class="p">)</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-9"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doMoreStuff</span><span class="p">)</span>
</pre><p>If anyone has any suggestions for other examples I should add to this list,
feel free to leave a comment or <a class="reference external" href="mailto:mithrandi@mithrandi.net">drop me a note</a>, and I'll consider updating
the post.</p>
</div>
</div></div><div><p>[NOTE: If you are reading this post in an RSS reader, the formatting on the
code examples may not be optimal; please read this in a web browser with
JavaScript enabled for the optimal viewing experience]</p>
<div class="section" id="introduction">
<h2>Introduction</h2>
<p>I often find myself helping newer Twisted users come to grips with arranging
their flow control when they first start writing code that uses Deferreds.
While the <a class="reference external" href="http://twistedmatrix.com/documents/current/core/howto/defer.html">Deferred Reference</a> does a reasonable job of covering all of the
details, it is often difficult to make the intuitive leap from the synchronous
patterns one is used to, to their asynchronous equivalents. To that end, I
often find that comparing sync and async versions is illustrative; there are
some examples of this nature in the Deferred Reference, but some patterns are
missing, and I've never actually put all of the examples down in one place, so
I thought I'd do that in my blog post. Without any further ado, here they are:</p>
<p>EDIT: Added composition example</p>
<div class="section" id="call-a-function-and-use-the-result">
<h3>Call a function, and use the result</h3>
<pre class="code python"><a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-2"></a><span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-3"></a><span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-4"></a>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-5"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-6"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_a365af659e9c43d7bad4c2bbacbf1eb6-7"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-catching-a-particular-exception">
<h3>Call a function and use the result, catching a particular exception</h3>
<pre class="code python"><a name="rest_code_0165eddc75814d19960d16eea78070e9-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-4"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-5"></a><span class="k">except</span> <span class="n">SomeException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-6"></a> <span class="n">handleError</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-7"></a>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-9"></a><span class="k">def</span> <span class="nf">_eb</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-10"></a> <span class="n">f</span><span class="o">.</span><span class="n">trap</span><span class="p">(</span><span class="n">SomeException</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-11"></a> <span class="n">handleError</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-12"></a>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-13"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-14"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
<a name="rest_code_0165eddc75814d19960d16eea78070e9-15"></a><span class="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">_eb</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-catching-any-exception">
<h3>Call a function and use the result, catching any exception</h3>
<pre class="code python"><a name="rest_code_8b58173953434680ba0eb12d0ab76452-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-4"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-5"></a><span class="k">except</span><span class="p">:</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-6"></a> <span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">()</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-7"></a>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-9"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-10"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
<a name="rest_code_8b58173953434680ba0eb12d0ab76452-11"></a><span class="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-catching-exceptions-raised-by-that-function">
<h3>Call a function and use the result, catching exceptions raised by that function</h3>
<pre class="code python"><a name="rest_code_1861872373f44de5afc681f330d29c6f-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-4"></a><span class="k">except</span><span class="p">:</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-5"></a> <span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">()</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-6"></a><span class="k">else</span><span class="p">:</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-7"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-8"></a>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-9"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-10"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_1861872373f44de5afc681f330d29c6f-11"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallbacks</span><span class="p">(</span><span class="n">doSomething</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">err</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-recovering-from-a-particular-exception-raised-by-the-function">
<h3>Call a function and use the result, recovering from a particular exception raised by the function</h3>
<pre class="code python"><a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-4"></a><span class="k">except</span> <span class="n">SomeException</span><span class="p">:</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-5"></a> <span class="n">result</span> <span class="o">=</span> <span class="mi">42</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-6"></a><span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-7"></a>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-9"></a><span class="k">def</span> <span class="nf">_eb</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-10"></a> <span class="n">f</span><span class="o">.</span><span class="n">trap</span><span class="p">(</span><span class="n">SomeException</span><span class="p">)</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-11"></a> <span class="k">return</span> <span class="mi">42</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-12"></a>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-13"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-14"></a><span class="n">d</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">_eb</span><span class="p">)</span>
<a name="rest_code_0ecaf6e5661a49f195a8708df211ff41-15"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
</pre></div>
<div class="section" id="call-a-function-and-use-the-result-performing-cleanup-if-an-exception-occurs">
<h3>Call a function and use the result, performing cleanup if an exception occurs</h3>
<pre class="code python"><a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-2"></a><span class="k">try</span><span class="p">:</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-3"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-4"></a> <span class="n">doSomething</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-5"></a><span class="k">finally</span><span class="p">:</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-6"></a> <span class="n">cleanStuffUp</span><span class="p">()</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-7"></a>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-8"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-9"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-10"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doSomething</span><span class="p">)</span>
<a name="rest_code_28f229315bff4c49adce0f1d2c4cba77-11"></a><span class="n">d</span><span class="o">.</span><span class="n">addBoth</span><span class="p">(</span><span class="k">lambda</span> <span class="n">ignored</span><span class="p">:</span> <span class="n">cleanStuffUp</span><span class="p">())</span>
</pre></div>
<div class="section" id="compose-several-functions">
<h3>Compose several functions</h3>
<pre class="code python"><a name="rest_code_7982cdb9875f49afbb5a669100280b60-1"></a><span class="c1"># Synchronous version</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-2"></a><span class="n">result</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-3"></a><span class="n">result2</span> <span class="o">=</span> <span class="n">doStuff</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-4"></a><span class="n">result3</span> <span class="o">=</span> <span class="n">doMoreStuff</span><span class="p">(</span><span class="n">result2</span><span class="p">)</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-5"></a>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-6"></a><span class="c1"># Asynchronous version</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-7"></a><span class="n">d</span> <span class="o">=</span> <span class="n">getSomething</span><span class="p">()</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-8"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doStuff</span><span class="p">)</span>
<a name="rest_code_7982cdb9875f49afbb5a669100280b60-9"></a><span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">doMoreStuff</span><span class="p">)</span>
</pre><p>If anyone has any suggestions for other examples I should add to this list,
feel free to leave a comment or <a class="reference external" href="mailto:mithrandi@mithrandi.net">drop me a note</a>, and I'll consider updating
the post.</p>
</div>
</div></div>Programming with event loopshttps://mithrandi.net/blog/2010/06/programming-with-event-loops/2010-06-18T20:48:54Z2010-06-18T20:48:54Zmithrandi<div><p>People new to working with event-driven programming in general, and event loops in particular, often seem to have a hard time figuring out how to run their code when it needs to be run. For example, the event loop in <a href="http://twistedmatrix.com/">Twisted</a> is called the reactor (or perhaps more accurately, the event loop is part of the reactor). The reactor can be started and stopped, but the catch is that the current implementation only allows you to start one reactor once per process. Once you’ve stopped it, it can’t be started again. Now, this is really just an unfortunate consequence of two historical design artifacts; the reactor is a global singleton, so you can only have one, and it doesn’t manage the process-global state well enough to be able to start again once it has stopped. However, while it would be nice for those two issues to be fixed, the reality is that the usual answer to “how do I stop and start the reactor more than once?” is “you don’t need to, and you don’t want to.”</p>
<p>The idea of an event loop is, roughly, “don’t call us, we’ll call you”. When an event occurs, the event loop takes care of dispatching that event to the relevant code in order to handle the event. While there may be some layers of library / framework between your application code and the low-level event handler, ultimately it’ll usually be some part of your application code that gets invoked in response to the event. This means that instead of writing your program in the style of “do A, then do B, then do C”, you write it in a way that looks more like “when X happens, do A; when Y happens, do B; when Z happens, do C”.</p>
<p>So, how do you kick things off? If you fire up an event loop without doing anything else, generally no events will ever occur / be received, and so your program will just run forever doing absolutely nothing. Thus, in the startup phase of your program before you start the event loop, you will need to perform some operations that will cause events to be received later on. For example, an HTTP server would probably want to open a socket and start listening on port 80; alternatively, you might have some time-based event, along the lines of “run this code every 30 seconds”. The startup phase is not the only time that you can set your event sources up; you can also do this in any of your application code that handles other events that occur. For example, your web server might open a connection to a database server when it receives a request for a certain URL.</p>
<p>That’s really all there is to it; figure out which event sources you need to set up intially before you run the event loop, and figure out what other events will occur during the lifetime of your application that would require setting up additional event sources, no matter what those event sources might be (making connections, starting timers, completion of a prior operation, etc). While this post may be slightly Twisted-specific, the concepts are pretty general: any decent event loop will necessarily allow both cases (initial setup, and additional operations while the event loop is running). The key is to think of your application as code run in response to events, not just a linear series of operations.</p></div><div><p>People new to working with event-driven programming in general, and event loops in particular, often seem to have a hard time figuring out how to run their code when it needs to be run. For example, the event loop in <a href="http://twistedmatrix.com/">Twisted</a> is called the reactor (or perhaps more accurately, the event loop is part of the reactor). The reactor can be started and stopped, but the catch is that the current implementation only allows you to start one reactor once per process. Once you’ve stopped it, it can’t be started again. Now, this is really just an unfortunate consequence of two historical design artifacts; the reactor is a global singleton, so you can only have one, and it doesn’t manage the process-global state well enough to be able to start again once it has stopped. However, while it would be nice for those two issues to be fixed, the reality is that the usual answer to “how do I stop and start the reactor more than once?” is “you don’t need to, and you don’t want to.”</p>
<p>The idea of an event loop is, roughly, “don’t call us, we’ll call you”. When an event occurs, the event loop takes care of dispatching that event to the relevant code in order to handle the event. While there may be some layers of library / framework between your application code and the low-level event handler, ultimately it’ll usually be some part of your application code that gets invoked in response to the event. This means that instead of writing your program in the style of “do A, then do B, then do C”, you write it in a way that looks more like “when X happens, do A; when Y happens, do B; when Z happens, do C”.</p>
<p>So, how do you kick things off? If you fire up an event loop without doing anything else, generally no events will ever occur / be received, and so your program will just run forever doing absolutely nothing. Thus, in the startup phase of your program before you start the event loop, you will need to perform some operations that will cause events to be received later on. For example, an HTTP server would probably want to open a socket and start listening on port 80; alternatively, you might have some time-based event, along the lines of “run this code every 30 seconds”. The startup phase is not the only time that you can set your event sources up; you can also do this in any of your application code that handles other events that occur. For example, your web server might open a connection to a database server when it receives a request for a certain URL.</p>
<p>That’s really all there is to it; figure out which event sources you need to set up intially before you run the event loop, and figure out what other events will occur during the lifetime of your application that would require setting up additional event sources, no matter what those event sources might be (making connections, starting timers, completion of a prior operation, etc). While this post may be slightly Twisted-specific, the concepts are pretty general: any decent event loop will necessarily allow both cases (initial setup, and additional operations while the event loop is running). The key is to think of your application as code run in response to events, not just a linear series of operations.</p></div>Why Mantissa?https://mithrandi.net/blog/2008/07/why-mantissa/2008-07-03T16:57:19Z2008-07-03T16:57:19Zmithrandi<div>
<p><a href="http://labs.twistedmatrix.com/2008/07/twisted-in-news.html">Seems</a> like <a href="http://syllogism.co.za/2008/07/thoughts-on-frameworks-why-i-u.html">everyone</a> is <a href="http://labs.twistedmatrix.com/2008/07/twisted-in-news.html">suddenly</a> <a href="http://oubiwann.blogspot.com/2008/07/divmod-tech-making-next-gen-grade.html">talking</a> about <a href="http://twistedmatrix.com/">Twisted</a> / <a href="http://divmod.org/">Divmod</a> / etc, so I thought I'd throw in some commentary on why I use <a href="http://divmod.org/trac/wiki/DivmodMantissa">Mantissa</a>. I'll start at the bottom of the stack, with Twisted. (If I start discussing "why *Python*?" I'll probably never finish this post!) The core of Twisted is an asynchronous network / I/O framework; around this core is a variety of code built on top of this framework: Twisted includes implementations of many network protocols, and has a number of useful abstractions that form part of those implementations.</p>
<p>One of the key principles that people in the Twisted community seem to generally subscribe to, is that the primary goal of a piece of code is to do the "right" thing. Of course, despite the best efforts of the great coding wizards, mistakes are still made, and manpower is always short, so the result is not always a perfect glistening gem of coding perfection; but the focus is still on "do it right". There is a mantra (attributed to a variety of people) that goes "Make it work, make it right, make it fast"; in my opinion, when that ordering is violated, the results are typically a disaster. Any codebase that achieves widespread use must at least get the "make it work" part done first, but often the next step is "make it fast"; not necessarily in the sense of the performance of the codebase, but also in terms of development effort. The result is an environment and culture that optimizes for getting the wrong thing done quickly, and in the process, typically making it harder or impossible to get the right thing done.</p>
<p>In many contexts, this isn't such a big deal; it's okay to get a result that is only "50%" or even "25%" in many cases, either just ignoring the breakage, or dealing with it piecemeal as you go along. Unfortunately (or fortunately, perhaps), I'm an idealist at heart. I retain enough pragmatism to operate in the real, flawed, world, but idealistic compromise is mentally unpleasant to me, so I avoid it as much as possible. There are mostly only two contexts I write code in: the personal context, where I'm doing it mostly for enjoyment, and thus have the freedom to be as idealistic as I want; and then the business context, where I'm being paid to make things work in the long-term, and need to produce high-quality results. So, either way, I'm looking to spend more time writing code that does the right thing (which ultimately saves me time in the long run), rather than worrying about getting any old junk working as quickly as possible, and this aligns perfectly with the attitude of the Twisted community, at least as I perceive it. Thus, while others complain with the learning curve involved with this stack, I have no problems spending the time needed to become familiar with everything I need to unlock the true power of the stack. In most cases, I find that I'm not "struggling" to learn the technology, it's just that it does so much more for me, that I need to spend more time finding out about how to use it, and ultimately saving myself far more time in the long run. The time spent learning is not time lost, but time invested.</p>
<p>So, Twisted provides asynchronous networking and protocol implementations, such as a web server; the layers of the stack above Twisted start to tie me down more in terms of architectural approach, but this is still an acceptable cost for me (although I wouldn't necessarily choose this set of technologies for every single project I write). <a href="http://divmod.org/trac/wiki/DivmodAxiom">Axiom</a> provides synchronous in-process database access, and more importantly, schema management. This frees me from the task of managing a separate database server process, while simultaneously providing a mapping from the database schema to data objects, and a framework ("upgraders") for managing changes in that schema (as opposed to the usual ad-hoc scripting approach that seems to be the norm).</p>
<p><a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow</a>… well, there are a lot of things wrong with Nevow; it contains large swathes of outdated code that should generally just be avoided, and some of the internals ("context", anyone?) are really awful, and need to be replaced. In addition, it ends up replacing half of twisted.web's webserver implementation; while this replacement is mostly for the better, that code really belongs back in twisted.web, instead of having the web server code schizophrenically split between the two codebases. Yet, despite all of that, Nevow still does a pretty good job of letting me do "the right thing", even if Nevow itself isn't always doing the right thing; the bad parts of Nevow are an eyesore, but it's not that hard to just ignore them, and use the good parts. The templating system has a heart of gold, allowing me to cleanly separate my templating markup, my rendering logic, and my data model. Add Athena to the mix, and I now have bi-directional communication between browser and server (COMET, if you like), and a JavaScript modules system that continues the theme of code separation, keeping my JavaScript separate from the rest; I also get a JavaScript class-based object model.</p>
<p>Mantissa sits atop the other elements of the stack, as the application server. It provides abstractions along application lines, allowing different applications (in the form of "offerings") to co-exist in the same Mantissa server, and along user lines, storing each user's data in their own Axiom store (database, and this is actually mostly an Axiom feature, although it has been argued that the code should be moved into Mantissa), and providing a "sharing" system to control access to the data in the users' stores. For the most part, Mantissa's functionality is currently web-based; but this is simply a matter of where the effort has been focused so far, and not a reflection of the underlying design — Mantissa's design is multi-protocol, allowing for an HTTP server sitting alongside anything else you might want (SMTP, IMAP, XMPP, SIP, whatever). This brings me to another important property that is pervasive within this stack; while Mantissa (and dependencies) may not have the popularity and thus the manpower that other projects enjoy, the components are typically designed in a fashion amenable to extension. If I need some functionality that nobody has had time to work on yet, I'll obviously have to write a fair amount of code to get the job done; but I typically won't have to overpower Mantissa in a brutal battle of wills just to get it to let me start working on what I want done. I simply provide the code for the parts that haven't been implemented yet, plugging them into the parts that *have* been implemented. This way I reap the benefits of the work that has been done by others without running into any nasty surprises later on once the need to go beyond that work arises; something that is essentially guaranteed to happen when working on any significantly large project.</p>
<p>In summary, I use Mantissa in a lot of my projects because it provides a lot of useful functionality that aids me in my quest to write good software, while at the same time getting out of my way when it comes time to go beyond the bounds of what it provides me with. Invariably, this choice means that certain architectural decisions have been made for me, decisions that can't easily be changed or reversed by building on top of the stack; for some projects, those decisions are inappropriate, and thus I'll c</p>
<p>hoose differently; but those decisions have usually been made by some pretty smart people, and are generally sound ones in the contexts in which they are appropriate.</p>
<p>Hopefully I've managed to convey the high-level attraction I have to Mantissa and related software; please note that I'm not trying to justify the low-level decisions involved here. Want to argue about how PostgreSQL is a superior database solution than SQLite? Why per-user database are a bad idea? How "COMET" and web applications that require JS are ruining the web? Sure, I'd be glad to have those discussions, but the point of this post was not to defend the specifics; think of it more as a window onto the development world I immerse myself in most of the time; and hopefully a little of my enthusiasm has been passed on to you!</p>
</div><div>
<p><a href="http://labs.twistedmatrix.com/2008/07/twisted-in-news.html">Seems</a> like <a href="http://syllogism.co.za/2008/07/thoughts-on-frameworks-why-i-u.html">everyone</a> is <a href="http://labs.twistedmatrix.com/2008/07/twisted-in-news.html">suddenly</a> <a href="http://oubiwann.blogspot.com/2008/07/divmod-tech-making-next-gen-grade.html">talking</a> about <a href="http://twistedmatrix.com/">Twisted</a> / <a href="http://divmod.org/">Divmod</a> / etc, so I thought I'd throw in some commentary on why I use <a href="http://divmod.org/trac/wiki/DivmodMantissa">Mantissa</a>. I'll start at the bottom of the stack, with Twisted. (If I start discussing "why *Python*?" I'll probably never finish this post!) The core of Twisted is an asynchronous network / I/O framework; around this core is a variety of code built on top of this framework: Twisted includes implementations of many network protocols, and has a number of useful abstractions that form part of those implementations.</p>
<p>One of the key principles that people in the Twisted community seem to generally subscribe to, is that the primary goal of a piece of code is to do the "right" thing. Of course, despite the best efforts of the great coding wizards, mistakes are still made, and manpower is always short, so the result is not always a perfect glistening gem of coding perfection; but the focus is still on "do it right". There is a mantra (attributed to a variety of people) that goes "Make it work, make it right, make it fast"; in my opinion, when that ordering is violated, the results are typically a disaster. Any codebase that achieves widespread use must at least get the "make it work" part done first, but often the next step is "make it fast"; not necessarily in the sense of the performance of the codebase, but also in terms of development effort. The result is an environment and culture that optimizes for getting the wrong thing done quickly, and in the process, typically making it harder or impossible to get the right thing done.</p>
<p>In many contexts, this isn't such a big deal; it's okay to get a result that is only "50%" or even "25%" in many cases, either just ignoring the breakage, or dealing with it piecemeal as you go along. Unfortunately (or fortunately, perhaps), I'm an idealist at heart. I retain enough pragmatism to operate in the real, flawed, world, but idealistic compromise is mentally unpleasant to me, so I avoid it as much as possible. There are mostly only two contexts I write code in: the personal context, where I'm doing it mostly for enjoyment, and thus have the freedom to be as idealistic as I want; and then the business context, where I'm being paid to make things work in the long-term, and need to produce high-quality results. So, either way, I'm looking to spend more time writing code that does the right thing (which ultimately saves me time in the long run), rather than worrying about getting any old junk working as quickly as possible, and this aligns perfectly with the attitude of the Twisted community, at least as I perceive it. Thus, while others complain with the learning curve involved with this stack, I have no problems spending the time needed to become familiar with everything I need to unlock the true power of the stack. In most cases, I find that I'm not "struggling" to learn the technology, it's just that it does so much more for me, that I need to spend more time finding out about how to use it, and ultimately saving myself far more time in the long run. The time spent learning is not time lost, but time invested.</p>
<p>So, Twisted provides asynchronous networking and protocol implementations, such as a web server; the layers of the stack above Twisted start to tie me down more in terms of architectural approach, but this is still an acceptable cost for me (although I wouldn't necessarily choose this set of technologies for every single project I write). <a href="http://divmod.org/trac/wiki/DivmodAxiom">Axiom</a> provides synchronous in-process database access, and more importantly, schema management. This frees me from the task of managing a separate database server process, while simultaneously providing a mapping from the database schema to data objects, and a framework ("upgraders") for managing changes in that schema (as opposed to the usual ad-hoc scripting approach that seems to be the norm).</p>
<p><a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow</a>… well, there are a lot of things wrong with Nevow; it contains large swathes of outdated code that should generally just be avoided, and some of the internals ("context", anyone?) are really awful, and need to be replaced. In addition, it ends up replacing half of twisted.web's webserver implementation; while this replacement is mostly for the better, that code really belongs back in twisted.web, instead of having the web server code schizophrenically split between the two codebases. Yet, despite all of that, Nevow still does a pretty good job of letting me do "the right thing", even if Nevow itself isn't always doing the right thing; the bad parts of Nevow are an eyesore, but it's not that hard to just ignore them, and use the good parts. The templating system has a heart of gold, allowing me to cleanly separate my templating markup, my rendering logic, and my data model. Add Athena to the mix, and I now have bi-directional communication between browser and server (COMET, if you like), and a JavaScript modules system that continues the theme of code separation, keeping my JavaScript separate from the rest; I also get a JavaScript class-based object model.</p>
<p>Mantissa sits atop the other elements of the stack, as the application server. It provides abstractions along application lines, allowing different applications (in the form of "offerings") to co-exist in the same Mantissa server, and along user lines, storing each user's data in their own Axiom store (database, and this is actually mostly an Axiom feature, although it has been argued that the code should be moved into Mantissa), and providing a "sharing" system to control access to the data in the users' stores. For the most part, Mantissa's functionality is currently web-based; but this is simply a matter of where the effort has been focused so far, and not a reflection of the underlying design — Mantissa's design is multi-protocol, allowing for an HTTP server sitting alongside anything else you might want (SMTP, IMAP, XMPP, SIP, whatever). This brings me to another important property that is pervasive within this stack; while Mantissa (and dependencies) may not have the popularity and thus the manpower that other projects enjoy, the components are typically designed in a fashion amenable to extension. If I need some functionality that nobody has had time to work on yet, I'll obviously have to write a fair amount of code to get the job done; but I typically won't have to overpower Mantissa in a brutal battle of wills just to get it to let me start working on what I want done. I simply provide the code for the parts that haven't been implemented yet, plugging them into the parts that *have* been implemented. This way I reap the benefits of the work that has been done by others without running into any nasty surprises later on once the need to go beyond that work arises; something that is essentially guaranteed to happen when working on any significantly large project.</p>
<p>In summary, I use Mantissa in a lot of my projects because it provides a lot of useful functionality that aids me in my quest to write good software, while at the same time getting out of my way when it comes time to go beyond the bounds of what it provides me with. Invariably, this choice means that certain architectural decisions have been made for me, decisions that can't easily be changed or reversed by building on top of the stack; for some projects, those decisions are inappropriate, and thus I'll c</p>
<p>hoose differently; but those decisions have usually been made by some pretty smart people, and are generally sound ones in the contexts in which they are appropriate.</p>
<p>Hopefully I've managed to convey the high-level attraction I have to Mantissa and related software; please note that I'm not trying to justify the low-level decisions involved here. Want to argue about how PostgreSQL is a superior database solution than SQLite? Why per-user database are a bad idea? How "COMET" and web applications that require JS are ruining the web? Sure, I'd be glad to have those discussions, but the point of this post was not to defend the specifics; think of it more as a window onto the development world I immerse myself in most of the time; and hopefully a little of my enthusiasm has been passed on to you!</p>
</div>Mantissa rockshttps://mithrandi.net/blog/2008/06/mantissa-rocks/2008-06-27T18:47:17Z2008-06-27T18:47:17Zmithrandi<div>
<p>Divmod Mantissa is an "application server" which I've been basing almost all of my applications on for a while now; this IRC conversation snippet is pretty illustrative of why I think Mantissa (and the rest of the stack, Twisted etc.) rocks.</p>
<blockquote><p><strong>< glyph</strong><strong>></strong> oubiwann: I think I've put my finger on why I don't like the serious use of acronyms like AJAX and LAMP<br><strong>< glyph></strong> oubiwann: they're just shibboleths for much simpler concepts<br><strong>< oubiwann></strong> glyph: why's that?<br><strong>< glyph></strong> oubiwann: AJAX is the magic word that means "Hey guys! Check this out! Javascript works now!"<br><strong></strong><strong>< glyph></strong> LAMP is the magic words that means "Hey uh, did you guys notice that PHP is almost completely broken without being attached to a database on the back end and a web server on the front end?"<br><strong>< glyph></strong> "AJAX" apps are Javascript apps, "LAMP" apps are PHP apps<br><strong>< glyph></strong> there's no additional information conveyed by the acronym, because all the peripheral crap that is pulled in doesn't make a difference<br><strong>< glyph></strong> lots of "LAMP" applications actually use postgres, or run on freebsd<br><strong>< glyph></strong> oubiwann: the reason we had so much trouble with *MAP, META, etc, is that there's actually no peripheral crap in our universe<br><strong>< glyph></strong> it's all part of the stack ;)</p>
</blockquote></div><div>
<p>Divmod Mantissa is an "application server" which I've been basing almost all of my applications on for a while now; this IRC conversation snippet is pretty illustrative of why I think Mantissa (and the rest of the stack, Twisted etc.) rocks.</p>
<blockquote><p><strong>< glyph</strong><strong>></strong> oubiwann: I think I've put my finger on why I don't like the serious use of acronyms like AJAX and LAMP<br><strong>< glyph></strong> oubiwann: they're just shibboleths for much simpler concepts<br><strong>< oubiwann></strong> glyph: why's that?<br><strong>< glyph></strong> oubiwann: AJAX is the magic word that means "Hey guys! Check this out! Javascript works now!"<br><strong></strong><strong>< glyph></strong> LAMP is the magic words that means "Hey uh, did you guys notice that PHP is almost completely broken without being attached to a database on the back end and a web server on the front end?"<br><strong>< glyph></strong> "AJAX" apps are Javascript apps, "LAMP" apps are PHP apps<br><strong>< glyph></strong> there's no additional information conveyed by the acronym, because all the peripheral crap that is pulled in doesn't make a difference<br><strong>< glyph></strong> lots of "LAMP" applications actually use postgres, or run on freebsd<br><strong>< glyph></strong> oubiwann: the reason we had so much trouble with *MAP, META, etc, is that there's actually no peripheral crap in our universe<br><strong>< glyph></strong> it's all part of the stack ;)</p>
</blockquote></div>Fusion production deploymenthttps://mithrandi.net/blog/2007/04/fusion-production-deployment/2007-04-01T23:05:00Z2007-04-01T23:05:00Zmithrandi<div><p><a name="d01t2105"></a></p>
<div>
<h5 class="tags">tags:</h5>
<ul class="tags">
<li><a rel="tag" href="http://technorati.com/tag/fusion"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> fusion</a></li>
<li><a rel="tag" href="http://technorati.com/tag/work"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> work</a></li>
<li><a rel="tag" href="http://technorati.com/tag/divmod"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> divmod</a></li>
<li><a rel="tag" href="http://technorati.com/tag/twisted"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> twisted</a></li>
</ul>
<p>I just finished deploying Fusion 1.0 to our production server. If you don’t know what that is, suffice it to say that it’s the new system I’ve been working on for the last 6 months or so, replacing the existing legacy system. If you’re wondering why I’m excited, not terrified, here is a snippet of code from the legacy system:</p>
<pre><code>printf([<input type="submit" value="Next Page" onClick="if (checkMatrix('MAINFORM', 'qmtx')] + ;
[ && checkMPStuff('MAINFORM', 'toolkitnum', 'qmp')] + ;
; //’ && checkReasons(%s)’ + ;
[ && confirm('Proceed with inception of selected products? This is irrevocable!')) changeAction('MAINFORM', 'MAKEPAGE.EXE'); else return false;" /></div>],;
{jsDict(getOptDatabases())})]]</code></pre>
<p>In case you’re interested, Fusion is deployed on top of the <a href="http://divmod.org/trac/wiki/DivmodMantissa">Divmod Mantissa</a> stack (which includes <a href="http://divmod.org/trac/wiki/DivmodAxiom">Axiom</a>, <a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow</a>, <a href="http://twistedmatrix.com/">Twisted</a>). Without these awesome Free Software projects, this would have been a much longer ride, and the resulting product would no doubt have been of far inferior quality; thanks to all the contributors that make these projects a reality!</p>
<p>Anyhow, that’s all for now. Coming up next… a series on JavaScript “features” that are likely to stab you in the face. Maybe even <a href="http://bash.org/?4281">over the internet</a>.</p>
</div></div><div><p><a name="d01t2105"></a></p>
<div>
<h5 class="tags">tags:</h5>
<ul class="tags">
<li><a rel="tag" href="http://technorati.com/tag/fusion"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> fusion</a></li>
<li><a rel="tag" href="http://technorati.com/tag/work"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> work</a></li>
<li><a rel="tag" href="http://technorati.com/tag/divmod"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> divmod</a></li>
<li><a rel="tag" href="http://technorati.com/tag/twisted"><img src="https://mithrandi.net/images/techtag" alt="[tag]"> twisted</a></li>
</ul>
<p>I just finished deploying Fusion 1.0 to our production server. If you don’t know what that is, suffice it to say that it’s the new system I’ve been working on for the last 6 months or so, replacing the existing legacy system. If you’re wondering why I’m excited, not terrified, here is a snippet of code from the legacy system:</p>
<pre><code>printf([<input type="submit" value="Next Page" onClick="if (checkMatrix('MAINFORM', 'qmtx')] + ;
[ && checkMPStuff('MAINFORM', 'toolkitnum', 'qmp')] + ;
; //’ && checkReasons(%s)’ + ;
[ && confirm('Proceed with inception of selected products? This is irrevocable!')) changeAction('MAINFORM', 'MAKEPAGE.EXE'); else return false;" /></div>],;
{jsDict(getOptDatabases())})]]</code></pre>
<p>In case you’re interested, Fusion is deployed on top of the <a href="http://divmod.org/trac/wiki/DivmodMantissa">Divmod Mantissa</a> stack (which includes <a href="http://divmod.org/trac/wiki/DivmodAxiom">Axiom</a>, <a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow</a>, <a href="http://twistedmatrix.com/">Twisted</a>). Without these awesome Free Software projects, this would have been a much longer ride, and the resulting product would no doubt have been of far inferior quality; thanks to all the contributors that make these projects a reality!</p>
<p>Anyhow, that’s all for now. Coming up next… a series on JavaScript “features” that are likely to stab you in the face. Maybe even <a href="http://bash.org/?4281">over the internet</a>.</p>
</div></div>