<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Zen and the Art of Programming &#187; Python</title>
	<atom:link href="http://programmingzen.com/category/programming-languages/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://programmingzen.com</link>
	<description>Meditations on programming, startups, and technology</description>
	<lastBuildDate>Mon, 16 Jan 2012 17:09:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Installing Python, Django, and DB2 on Ubuntu 11.04</title>
		<link>http://programmingzen.com/2011/05/12/installing-python-django-and-db2-on-ubuntu-11-04/</link>
		<comments>http://programmingzen.com/2011/05/12/installing-python-django-and-db2-on-ubuntu-11-04/#comments</comments>
		<pubDate>Fri, 13 May 2011 09:06:58 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://programmingzen.com/?p=1375</guid>
		<description><![CDATA[Note: This is the Python version of the Ruby guide I just published. In this brief tutorial I’ll show you how to create a complete Python and Django setup for DB2 on Ubuntu. By following my step-by-step instructions, you’ll be able to install the following components: Python easy_install Django DB2 Express-C 9.7.4 The official Python [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p><em>Note: This is the Python version of the <a href="http://programmingzen.com/2011/05/11/installing-ruby-on-rails-and-db2-on-ubuntu-11-04/">Ruby guide</a> I just published.</em></p>
<p>In this brief tutorial I’ll show you how to create a complete Python and Django setup for DB2 on Ubuntu. By following my step-by-step instructions, you’ll be able to install the following components:</p>
<ul>
<li>Python</li>
<li>easy_install</li>
<li>Django</li>
<li><a href="http://db2express.com/download/?S_TACT=ACDB201">DB2 Express-C 9.7.4</a></li>
<li>The official <a href="http://code.google.com/p/ibm-db/">Python driver, dbi module, and Django adapter</a> for DB2</li>
</ul>
<h3 id="installing_python_and_easy_install">Installing Python and easy_install</h3>
<p>Technically Python is already installed on Ubuntu, so we don’t have to install it. However, we need the <code>python-dev</code> package in order to build the DB2 driver from source. We’ll also need easy_install which is included in the <code>python-setuptools</code> Ubuntu .deb:</p>
<pre class="highlight">$ sudo apt-get install python-dev python-setuptools</pre>
<p></p>
<h3 id="installing_django">Installing Django</h3>
<p>Now that we have easy_install available, we can easily install Django by running:</p>
<pre class="highlight">$ sudo easy_install django</pre>
<p>You can verify the installed version by running:</p>
<pre class="highlight">$ python</pre>
<p>And then executing the following snippet in the REPL:</p>
<pre class="highlight">>>> import django
>>> django.VERSION
(1, 3, 0, 'final', 0)</pre>
<p>At this time, version 1.3.0 should get installed as shown above.</p>
<h3 id="installing_db2">Installing DB2</h3>
<p>We can now download and install DB2 Express-C 9.7.4. <a href="http://db2express.com/download/?S_TACT=ACDB201">Download the .tar.gz file</a> to a location that’s convenient for you. Then proceed to unpack it:</p>
<pre class="highlight">$ cd ~/Downloads/
$ tar xvfz db2exc_974_LNX_x86.tar.gz
$ cd expc</pre>
<p>We’ll install one required library and then proceed with the setup:</p>
<pre class="highlight">$ sudo apt-get install libaio1
$ sudo ./db2setup</pre>
<p>Follow the GUI wizard on screen to continue with the installation. Pay close attention to two steps:</p>
<ul>
<li>When prompted <strong>select a custom installation</strong>, and when choosing the components, select all of them. We’ll need the <strong>Application Development Tools</strong> in order to build the Python driver later on (and these are unchecked by default).</li>
<li>When asked if you’d like to <strong>create an instance user</strong>, go with that option. It greatly simplifies the setup process.</li>
</ul>
<p>When the setup of DB2 is completed, you should receive a confirmation message informing you about the successful installation</p>
<p>For good measure, add the following line to your <code>~/.bashrc</code> file:</p>
<pre class="highlight">. /home/db2inst1/sqllib/db2profile</pre>
<p>This ensures that even your regular, non-DB2, user will be able to connect and interact with the database.</p>
<h3>Installing the Python driver and Django adapter</h3>
<p>The last step we need to take is to install the <code>ibm_db</code> Python driver and the <code>ibm_db_dbi</code> module, as well as the Django adapter for DB2. These are all IBM supported, open source releases.</p>
<p>Open a new shell and run:</p>
<pre class="highlight">$ sudo -s
$ export IBM_DB_DIR=/home/db2inst1/sqllib
$ export IBM_DB_LIB=/home/db2inst1/sqllib/lib
$ . /home/db2inst1/sqllib/db2profile
$ easy_install ibm_db ibm_db_django
$ exit</pre>
<h3 id="a_quick_sanity_test">A quick sanity test</h3>
<p>To ensure that all is well with your setup, run the following command:</p>
<pre class="highlight">$ django-admin.py startproject db2test
$ cd db2test</pre>
<p>Now edit <code>settings.py</code> so ENGINE is set to <code>ibm_db_django</code>, NAME to a database like <code>db2test</code>, USER to <code>db2inst1</code>, PASSWORD to the same password you specified for the db2inst1 user during the installation of DB2. Use <code>localhost</code> for the HOST, and <code>50000</code> as the port number:</p>
<pre class="highlight">DATABASES = {
    'default': {
        'ENGINE': 'ibm_db_django',
        'NAME': 'db2test',
        'USER': 'db2inst1',
        'PASSWORD': 'secret',
        'HOST': 'localhost',
        'PORT': '50000',
    }
}</pre>
<p>Create the database <code>db2test</code> by running:</p>
<pre class="highlight">$ su - db2inst1
$ db2start
$ db2 create db db2test
$ exit</pre>
<p>Depending on your hardware specs, the infrequent operation of creating a database can take a bit of time (e.g., several minutes).</p>
<p>We will now run the actual test:</p>
<pre class="highlight">$ python manage.py test</pre>
<p>Unless exceptions are raised during this last step, you should be all set to use Django with DB2.</p>
<h3 id="if_you_need_help">If you need help</h3>
<p>IBM is the only database vendor to officially provide and support its Python driver and Django adapter. While commercial DB2 support is available and relatively <a href="http://www.db2teamblog.com/2010/12/treat-yourself-to-db2-this-holiday.html">inexpensive</a>, your first line of defense is posing your questions in the <a href="http://groups.google.com/group/ibm_db?pli=1">support forum</a> over at Google. Alternatively, if the question is DB2-specific and not related to Python/Django, you can use the <a href="http://www.ibm.com/developerworks/forums/forum.jspa?forumID=805">DB2 Express-C forum</a> over at developerWorks instead.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2011/05/12/installing-python-django-and-db2-on-ubuntu-11-04/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>FAQ: What programming language should I learn first?</title>
		<link>http://programmingzen.com/2011/03/28/what-programming-language-should-i-learn-first/</link>
		<comments>http://programmingzen.com/2011/03/28/what-programming-language-should-i-learn-first/#comments</comments>
		<pubDate>Mon, 28 Mar 2011 22:00:54 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[FAQs]]></category>
		<category><![CDATA[Programming Languages]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://programmingzen.com/?p=1328</guid>
		<description><![CDATA[There are hundreds of different programming languages out there. As a newcomer you can ignore the fact that most of them exist. However, even if we narrow the list to just a dozen mainstream languages, deciding on what programming language to learn first can be a daunting task. You might find yourself asking, should I [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p><img src="http://programmingzen.com/wp-content/uploads/2011/03/python-logo-master-v3-TM-e1301349063786.png" alt="Python Logo" title="Python Logo" width="250" height="84" style="float: right;" align="right" />There are hundreds of different programming languages out there. As a newcomer you can ignore the fact that most of them exist. However, even if we narrow the list to just a dozen mainstream languages, deciding on what programming language to learn first can be a daunting task. You might find yourself asking, should I learn C, C++, Java, C#, or PHP first? If you ask ten programmers this question, you&#8217;ll probably hear ten different answers. Here is my take.</p>
<p>Much as with human languages, programming languages are used to communicate. Interestingly they still involve communication between people, whether other programmers will end up reading/modifying/enhancing your code or you’ll do at a later point in time. Unlike natural languages however, programming languages are unequivocally understood by computers, thanks to the aid of interpreters, compilers, and similar types of software.</p>
<p>Depending on the kind of program you’re trying to write, and in which environment you’re working, you’ll find that some programming languages are better suited than others for certain tasks, even if most common programming languages are labelled as being &#8220;general purpose&#8221;.</p>
<p>For example, if you want to create iPhone and iPad applications, your best bet would be to use Objective-C. For Android smartphones and tablets, in most cases, you&#8217;ll need to become accustomed with Java. If you want to build web applications, you&#8217;ll want to learn client-side technologies such as HTML, CSS and JavaScript (of those three only JavaScript is an actual programming language, but the other two are necessary nevertheless). For the server-side of your web application, you&#8217;ll probably want to learn a language like PHP, Ruby, or Python (all three have frameworks that will help make most web programming tasks easier and less time consuming), rather than a system programming favorite like C. (And of course, one has to mention SQL if you’re interfacing with a relational database).</p>
<p>So should you start your foray into the world of programming languages with JavaScript? What about Objective-C? SQL? My advice is to avoid starting your programming journey with a language that is tailored to a specific environment. This early in the game, your main objective is to learn how to program &#8211; and how to reason like a programmer &#8211; rather than learning a specific language. Once you have mastered the fundamental concepts with the aid of a general purpose programming language, you can ease into other languages as the need arises, depending on the type of software you&#8217;d like to develop.</p>
<p>This is a profession where most of your skills are developed and honed by actually “doing”. If you grasp the fundamentals of programming outright, you can easily pick up a specific language and framework when you need to build iPad applications or whatever else you’d like to create.</p>
<p>A well-rounded programmer will end up learning several programming languages and tools over the course of their career. That said, if you are just starting out, focus on one language first. While this might seem a tad dull on the surface, the good news is that unless you pick a truly exotic programming language, a lot of what you learn will be applicable to other programming languages as well. Remember that at this stage, above all else, you are learning how to communicate your thoughts in precise statements for other programmers to understand (and for the computer to execute).</p>
<p>For this reason, you can&#8217;t really go too wrong with any of the &#8220;somewhat mainstream&#8221;, general purpose programming languages (e.g., C, Java, C#, Perl, Ruby, Python, or Scheme). That said, particularly if you are learning on your own, I&#8217;d advise that you go with a language that will make your learning trek easier. In other words, opt for a programming language that is widely used, well documented, and beginner-friendly. You’re looking for one that isn&#8217;t overly bureaucratic, doesn&#8217;t require you to manage memory directly, or have a deep understanding of mathematics to get started.</p>
<p>As such, my suggestion would be to start with Python, and use it as a tool to learn the general craft of programming. Learning Python is fun, easy, and useful. You’ll be able to use it for a wide array of projects in several environments (scripting, web, scientific research, etc&#8230;).</p>
<p>There are <a href="https://encrypted.google.com/search?hl=en&#038;source=hp&#038;biw=1401&#038;bih=740&#038;q=python+tutorial&#038;aq=f&#038;aqi=g10&#038;aql=&#038;oq=">a variety of free tutorials</a> on the web, but if you want a more rigorous/systematic/academic introduction, I highly recommend &#8220;<a href="/recommends/?1590282418" target="_blank" rel="nofollow">Python Programming: An Introduction to Computer Science (2nd Edition)</a>&#8221; (<a href="/recommends/?1590282418" target="_blank" rel="nofollow">USA</a> | <a href="http://www.amazon.co.uk/gp/product/1590282418/ref=as_li_qf_sp_asin_tl?ie=UTF8&#038;tag=zenruby-21&#038;linkCode=as2&#038;camp=1634&#038;creative=6738&#038;creativeASIN=1590282418" target="_blank" rel="nofollow">UK</a> | <a href="http://www.amazon.ca/gp/product/1590282418/ref=as_li_qf_sp_asin_tl?ie=UTF8&#038;tag=zenrubyca-20&#038;link_code=as3&#038;camp=212553&#038;creative=381305&#038;creativeASIN=1590282418" target="_blank" rel="nofollow">Canada</a>).</p>
<p>Once you have learned the fundamentals of programming, have a decent command of the Python language, and have gained some experience with practical Python projects, you should be better armed to evaluate and pick up other languages and frameworks based on the projects you intend to develop or contribute to in the future (Open Source projects are awesome for this purpose).</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2011/03/28/what-programming-language-should-i-learn-first/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Thoughts on Clojure</title>
		<link>http://programmingzen.com/2010/07/09/thoughts-on-clojure/</link>
		<comments>http://programmingzen.com/2010/07/09/thoughts-on-clojure/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 18:00:32 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://programmingzen.com/?p=1225</guid>
		<description><![CDATA[Lisp has had a tremendous impact on the world of programming. Even though Common Lisp and Scheme &#8212; the two main Lisp dialects &#8212; may not be considered mainstream today, several popular languages have been influenced by one or both of them. It isn&#8217;t stretching things too much to say that both Ruby and Python [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Lisp has had a tremendous impact on the world of programming. Even though Common Lisp and Scheme &mdash; the two main Lisp dialects &mdash; may not be considered mainstream today, several popular languages have been influenced by one or both of them.</p>
<p>It isn&#8217;t stretching things too much to say that both Ruby and Python can be seen as slower, easier (for beginners), object-oriented, infix Lisp dialects.</p>
<blockquote><p>Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people. &mdash; Yukihiro &#8220;Matz&#8221; Matsumoto</p></blockquote>
<p>Ruby and Python aren&#8217;t intimidating and remain very approachable for absolute beginners. Furthermore, their approachability is not confined to the language design itself, but transcends into the community and ecosystem that surrounds them.</p>
<p>I&#8217;m not here to discuss how languages like Ruby and Python managed to become more popular than major Lisp dialects nowadays. I&#8217;d rather focus on how these gentler introductions to functional programming are acting as gateway drugs to Lisp for many developers.</p>
<p>A community that values metaprogramming and is obsessed with the construction of DSLs (Domain Specific Languages) like the Ruby&#8217;s is, will no doubt find in Lisp a valuable ally. Plus, if you know Ruby inside and out, you should find Lisp to be easy enough to learn.</p>
<p>To attract Ruby developers though, Lisp has to offer something more than just a set of powerful features. You could say that Rails is enough of a reason to learn and use Ruby. But what is Lisp able to solve all that better than Ruby? I&#8217;ll answer that question by focusing on a specific dialect of Lisp, that I and continually more Ruby developers are getting into: <a href="http://clojure.org">Clojure</a>.</p>
<p>It wouldn&#8217;t be fair to characterize the Lisp community as stagnant, but Clojure is definitely a welcomed dose of new blood. Clojure is a JVM-based modern Lisp designed for concurrency, which elegantly includes a set of carefully chosen features that are not easily found in mainstream languages.</p>
<p>In my opinion, Clojure has three main advantages over Ruby:</p>
<ul>
<li>It&#8217;s much faster than Ruby, which makes it a better choice for intensive processing. (<a href="http://www.infoq.com/articles/flightcaster-clojure-rails">FlightCaster</a> for example, uses both Rails and Clojure. Rails for the &#8220;front-end&#8221; and Clojure for the heavy lifting/forecasting.)</li>
<li>It greatly simplifies concurrent programming, making the language more future-proof as hardware manufacturers continue to produce processors with more CPU cores.</li>
<li>Clojure emphasizes functional programming and tries to minimize side effects.</li>
</ul>
<p>Clojure&#8217;s interoperability with Java resolves the issue of only having a few available libraries, which often affects new languages. It also helps in getting people to use the language within the enterprise world where Java still dominates.</p>
<p>Of all the &#8220;new&#8221; languages out there, I find Clojure to be the most fun, interesting and pragmatic: it&#8217;s something worth getting excited about. I don&#8217;t really care if it turns out to be the next Ruby or not, it&#8217;s a language that&#8217;s worth knowing and using. (If you haven&#8217;t tried it yet, a decent, short introductory book is the recently published <a href="http://programmingzen.com/recommends/?1430272317">Practical Clojure</a>.)</p>
<p>Clojure&#8217;s popularity may even bring more attention to Lisp in general (for example, most <a href="http://programmingzen.com/recommends/?0262011530">must-read</a> literature uses Scheme or Common Lisp). Perhaps then, it may indirectly help introduce more traditional Lisp dialects to a new generation of programmers.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2010/07/09/thoughts-on-clojure/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>DB2 support for Django 1.2 is here</title>
		<link>http://programmingzen.com/2010/03/30/db2-support-for-django-1-2-is-here/</link>
		<comments>http://programmingzen.com/2010/03/30/db2-support-for-django-1-2-is-here/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 02:32:02 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1135</guid>
		<description><![CDATA[The latest release of the IBM Adapter for Django now supports Django 1.2. Aside from enabling you to use the most recent version of Django, this release adds a few new goodies into the mix, that I&#8217;m sure many will appreciate. For example, IBM&#8217;s adapter (through the underlying DBI wrapper) now uses persistent connections, which [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://code.google.com/p/ibm-db/">latest release</a> of the <span class="caps">IBM</span> Adapter for Django now supports <a href="http://code.djangoproject.com/wiki/Version1.2Roadmap">Django 1.2</a>. Aside from enabling you to use the most recent version of Django, this release adds a few new goodies into the mix, that I&#8217;m sure many will appreciate.</p>
<p>For example, IBM&#8217;s adapter (through the underlying <span class="caps">DBI</span> wrapper) now uses persistent connections, which are especially helpful when dealing with Django &#8211; as it lacks connection pooling. (Of course DB2 also has the Connection Concentrator to aid in reducing the usage of server resources and improving scalability.)</p>
<p>Furthermore, the adapter adds support for the <span class="caps">DECIMAL</span> datatype, a necessary feature when dealing with money and currencies. Various enhancements and bug fixes were included too; <a href="http://groups.google.com/group/ibm_db/browse_thread/thread/c842df0e8803e517">check</a> <a href="http://groups.google.com/group/ibm_db/browse_thread/thread/2cb45b1b966f8a8c">them</a> out on Google Groups.</p>
<p>As a reminder, <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2 Express-C</a> is an absolutely free of charge version of DB2 and it&#8217;s production ready (not a toy version). You can <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">download it from here</a>. Take it for a spin, experiment &#8211; chances are you&#8217;ll like it. If you need a guide to getting started, be sure to check out this <a href="http://www.ibm.com/developerworks/wikis/display/db2/free+book-+getting+started+with+db2+express-c">free e-book</a> by my colleagues Raul, Ian, and Rav.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2010/03/30/db2-support-for-django-1-2-is-here/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Free Python screencast about solving mazes</title>
		<link>http://programmingzen.com/2010/03/29/free-python-screencast-about-solving-mazes/</link>
		<comments>http://programmingzen.com/2010/03/29/free-python-screencast-about-solving-mazes/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 12:00:26 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Screencasts]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1133</guid>
		<description><![CDATA[ThinkCode.TV&#8217;s English site is going to be launched on April 19th. To celebrate the upcoming launch and whet your appetite, a 19 minute long screencast about solving ASCII mazes with a few lines of Python code was just released for free. This video serves to illustrate Python&#8217;s elegance and power, as well as ThinkCode.TV&#8217;s approach [...]
Possibly related posts:<ol>
<li><a href='http://programmingzen.com/2009/05/25/announcing-thinkcodetvs-new-english-newsletter/' rel='bookmark' title='Announcing ThinkCode.TV&#8217;s new English newsletter'>Announcing ThinkCode.TV&#8217;s new English newsletter</a></li>
<li><a href='http://programmingzen.com/2009/05/14/ruby-19-screencasts-plus-an-announcement/' rel='bookmark' title='Ruby 1.9 screencasts plus an announcement'>Ruby 1.9 screencasts plus an announcement</a></li>
<li><a href='http://programmingzen.com/2009/04/27/screencast-on-how-to-install-db2-express-c-on-mac-os-x/' rel='bookmark' title='Screencast on how to install DB2 Express-C on Mac OS X'>Screencast on how to install DB2 Express-C on Mac OS X</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>ThinkCode.TV&#8217;s English site is going to be launched on April 19th. To celebrate the upcoming launch and whet your appetite, a 19 minute long screencast about solving ASCII mazes with a few lines of Python code was just released for free. This video serves to illustrate Python&#8217;s elegance and power, as well as ThinkCode.TV&#8217;s approach to screencasts and education.</p>
<p align="center"><a href="http://thinkcode.tv/free"><img src="http://antoniocangiano.com/wp-content/uploads/2010/03/pybite.png" alt="Free Python Screencast" title="A-mazing Python" style="border: none;" /></a></p>
<p>In order to download the screencast, you don&#8217;t need a credit card, to provide your address or even your last name. Just <a href="http://thinkcode.tv/free"><strong>head on over to this page</strong></a> and join the newsletter. Upon confirming your subscription, you will immediately receive an email with links to DRM-free, 720p HD files in the formats QuickTime Movie (.mov), AVI and Ogg Theora (.ogv). These videos are in English, prepared by a published serial author on the subject of Python/Django, and narrated by a native English speaker. They also include optional subtitles in the .srt format, as well as the source code which is released under the MIT license, as is customary for ThinkCode.TV to do.</p>
<p>I hope you enjoy the free screencast and stay tuned for the launch in three weeks. </p>
<p>Possibly related posts:<ol>
<li><a href='http://programmingzen.com/2009/05/25/announcing-thinkcodetvs-new-english-newsletter/' rel='bookmark' title='Announcing ThinkCode.TV&#8217;s new English newsletter'>Announcing ThinkCode.TV&#8217;s new English newsletter</a></li>
<li><a href='http://programmingzen.com/2009/05/14/ruby-19-screencasts-plus-an-announcement/' rel='bookmark' title='Ruby 1.9 screencasts plus an announcement'>Ruby 1.9 screencasts plus an announcement</a></li>
<li><a href='http://programmingzen.com/2009/04/27/screencast-on-how-to-install-db2-express-c-on-mac-os-x/' rel='bookmark' title='Screencast on how to install DB2 Express-C on Mac OS X'>Screencast on how to install DB2 Express-C on Mac OS X</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2010/03/29/free-python-screencast-about-solving-mazes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Benchmarking Tornado vs. Twisted Web vs. Tornado on Twisted</title>
		<link>http://programmingzen.com/2009/09/13/benchmarking-tornado-vs-twisted-web-vs-tornado-on-twisted/</link>
		<comments>http://programmingzen.com/2009/09/13/benchmarking-tornado-vs-twisted-web-vs-tornado-on-twisted/#comments</comments>
		<pubDate>Sun, 13 Sep 2009 12:07:51 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1104</guid>
		<description><![CDATA[FriendFeed, which was recently acquired by Facebook, just released an interesting piece of open source software. Tornado is an open source version of the scalable, non-blocking web server and tools that power FriendFeed. The FriendFeed application is written using a web framework that looks a bit like web.py or Google&#8217;s webapp, but with additional tools [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>FriendFeed, which was recently acquired by Facebook, just released an interesting piece of open source software.</p>
<blockquote><p><a href="http://www.tornadoweb.org/">Tornado</a> is an open source version of the scalable, non-blocking web server and tools that power FriendFeed. The FriendFeed application is written using a web framework that looks a bit like web.py or Google&#8217;s webapp, but with additional tools and optimizations to take advantage of the underlying non-blocking infrastructure.</p></blockquote>
<p><big><strong>The story so far</strong></big></p>
<p>This release generated widespread interest among the Python and open source development communities. Rightfully so. There are many reasons to like Tornado. To begin with, it&#8217;s fast &mdash; and that&#8217;s fundamental for a web server. By using nginx as a load balancer and a static file server, and running a few Tornado instances (usually one per core available on the machine) it&#8217;s possible to handle thousands upon thousands of concurrent connections on relatively modest hardware; and this isn&#8217;t just theory. Tornado has already proven its worth in the field, by allowing FriendFeed to scale graciously.</p>
<p>Tornado is not only a fast web server, it acts as a very lightweight application framework as well. As such, it&#8217;s an appealing alternative to well established frameworks to the growing group of developers who&#8217;d like to develop &#8220;closer to the metal&#8221; and avoid the baggage associated with full-fledged web frameworks. The two things combined make Tornado ideal for developing &#8220;real time&#8221; web services and applications.</p>
<p>The feedback so far hasn&#8217;t been all positive though. <a href="http://glyph.twistedmatrix.com/2009/09/what-i-wish-tornado-were.html">Criticism of the project</a> has mainly focused on the lack of test coverage and the fact that FriendFeed has opted not to contribute to, and improve on, the existing Twisted Web project (which has similar goals). To make things worse, there were a few nonchalant comments about it as well. Performance issues and lack of ease of use were the reported motivations for starting a new project from scratch.</p>
<p>Dustin Sallings started working on a hybrid solution (henceforth <a href="http://dustin.github.com/2009/09/12/tornado.html">Tornado on Twisted</a>) that would reportedly keep the good parts that Tornado introduced, while using Twisted as its core for networking and HTTP parsing.</p>
<p>At this point I became naturally curious about the speed of these three web servers. Is Tornado really faster than Twisted Web? And what about Tornado on Twisted, would it be faster or slower? Let&#8217;s find out.</p>
<p><big><strong>Benchmark results</strong></big></p>
<p>I ran a simple Hello World app for all three web servers. All the web servers were run in standalone mode without a load balancer. I stress tested the web servers with httperf using a progressively larger amount of concurrent requests. 100,000 requests were generated for each test. The web servers were run on a desktop machine with an Intel® Core™2 Quad Processor Q6600 (8M Cache, 2.40 GHz, 1066 MHz FSB) processor and 8GB of RAM. The operating system of choice was Ubuntu 9.04 (x86_64).</p>
<p>Without further ado, here are the results:</p>
<p align="center"><img src="http://antoniocangiano.com/images/python-throughput.png" alt="Throughput for Tornado, Twisted, and Tornado on Twisted" /></p>
<p>As you can see Tornado turned out to be faster than the rest of the Python web servers. Handling a peak of almost 3900 req/s with a single front-end and on commodity hardware is nothing to sneer at.</p>
<p>Twisted Web didn&#8217;t do too bad either (max. 2703.7 req/s), but the difference in performance is noticeable. Likewise, the performance of Tornado on Twisted was virtually identical to that of Twisted Web.</p>
<p>There you have it. I was curious about the possible outcome and now I know. Remember, this is a report on the numbers I got on my machine, not a research paper. But I hope that you find them interesting nevertheless.</p>
<p><big><strong>Show me the code</strong></big></p>
<p>Tornado:</p>
<div class="highlight">
<pre>
<span class="kn">import</span> <span class="nn">tornado.httpserver</span>
<span class="kn">import</span> <span class="nn">tornado.ioloop</span>
<span class="kn">import</span> <span class="nn">tornado.options</span>
<span class="kn">import</span> <span class="nn">tornado.web</span>
<span class="kn">import</span> <span class="nn">logging</span>

<span class="kn">from</span> <span class="nn">tornado.options</span> <span class="kn">import</span> <span class="n">define</span><span class="p">,</span> <span class="n">options</span>

<span class="n">define</span><span class="p">(</span><span class="s">&quot;port&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mf">8888</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">&quot;run on the given port&quot;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">MainHandler</span><span class="p">(</span><span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">RequestHandler</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;Hello, world!&quot;</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">tornado</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">()</span>
    <span class="n">application</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">Application</span><span class="p">([</span>
        <span class="p">(</span><span class="s">r&quot;/&quot;</span><span class="p">,</span> <span class="n">MainHandler</span><span class="p">),</span>
    <span class="p">])</span>
    <span class="n">http_server</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">httpserver</span><span class="o">.</span><span class="n">HTTPServer</span><span class="p">(</span><span class="n">application</span><span class="p">)</span>
    <span class="n">http_server</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">port</span><span class="p">)</span>
    <span class="n">tornado</span><span class="o">.</span><span class="n">ioloop</span><span class="o">.</span><span class="n">IOLoop</span><span class="o">.</span><span class="n">instance</span><span class="p">()</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre>
</div>
<p>Twisted Web:</p>
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">epollreactor</span>
<span class="n">epollreactor</span><span class="o">.</span><span class="n">install</span><span class="p">()</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span>
<span class="kn">from</span> <span class="nn">twisted.web</span> <span class="kn">import</span> <span class="n">server</span><span class="p">,</span> <span class="n">resource</span>

<span class="k">class</span> <span class="nc">Simple</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">Resource</span><span class="p">):</span>
    <span class="n">isLeaf</span> <span class="o">=</span> <span class="bp">True</span>
    <span class="k">def</span> <span class="nf">render_GET</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&quot;Hello, world!&quot;</span>

<span class="n">site</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">Site</span><span class="p">(</span><span class="n">Simple</span><span class="p">())</span>
<span class="n">reactor</span><span class="o">.</span><span class="n">listenTCP</span><span class="p">(</span><span class="mf">8888</span><span class="p">,</span> <span class="n">site</span><span class="p">)</span>
<span class="n">reactor</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</pre>
</div>
<p>Tornado on Twisted:</p>
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">epollreactor</span>
<span class="n">epollreactor</span><span class="o">.</span><span class="n">install</span><span class="p">()</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span>

<span class="kn">import</span> <span class="nn">tornado.options</span>
<span class="kn">import</span> <span class="nn">tornado.twister</span>
<span class="kn">import</span> <span class="nn">tornado.web</span>
<span class="kn">import</span> <span class="nn">logging</span>

<span class="kn">from</span> <span class="nn">tornado.options</span> <span class="kn">import</span> <span class="n">define</span><span class="p">,</span> <span class="n">options</span>

<span class="n">define</span><span class="p">(</span><span class="s">&quot;port&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mf">8888</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">&quot;run on the given port&quot;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">MainHandler</span><span class="p">(</span><span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">RequestHandler</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;Hello, world!&quot;</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">tornado</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">()</span>
    <span class="n">application</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">Application</span><span class="p">([</span>
        <span class="p">(</span><span class="s">r&quot;/&quot;</span><span class="p">,</span> <span class="n">MainHandler</span><span class="p">),</span>
    <span class="p">])</span>

    <span class="n">site</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">twister</span><span class="o">.</span><span class="n">TornadoSite</span><span class="p">(</span><span class="n">application</span><span class="p">)</span>
    <span class="n">reactor</span><span class="o">.</span><span class="n">listenTCP</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">port</span><span class="p">,</span> <span class="n">site</span><span class="p">)</span>

    <span class="n">reactor</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre>
</div>
<p><strong>UPDATE (September 14, 2009):</strong></p>
<ul>
<li>The original version of this post included Unicorn as well. This wasn&#8217;t fair however, since it&#8217;s not an asynchronous web server.</li>
<li>EventMachine HTTP Server was added, but I have since decided to remove it as I prefer to let the article be a fair comparison between asynchronous Python web servers.</li>
<li>I initially used Apache Benchmark (ab). The results were misleading at best. I re-ran the tests with httperf and updated the results above.</li>
<li>Stock Tornado couldn&#8217;t be tested with httperf because their HTTP Server doesn&#8217;t implement getClientIP(). I had to manually modify a method to return the remote ip address. This may introduce a very minimal advantage for Tornado, but it should be negligible in this context.</li>
<li>I modified the examples for Twisted and Tornado on Twisted, to ensure that both took advantage of the epoll-based reactor.</li>
</ul>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/09/13/benchmarking-tornado-vs-twisted-web-vs-tornado-on-twisted/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Improve the speed and security of your SQL queries</title>
		<link>http://programmingzen.com/2009/09/09/improve-the-speed-and-security-of-your-sql-queries/</link>
		<comments>http://programmingzen.com/2009/09/09/improve-the-speed-and-security-of-your-sql-queries/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 05:15:38 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1101</guid>
		<description><![CDATA[An easy way to improve the performance and security of SQL queries is to replace literals with parameters. By replacing literal values with parameters, advanced relational databases will be able to compile your queries and have their execution plans cached. This saves time and precious resources when the same query (minus the actual values) is executed [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>An easy way to improve the performance and security of SQL queries is to replace literals with parameters. By replacing literal values with parameters, advanced relational databases will be able to compile your queries and have their execution plans cached. This saves time and precious resources when the same query (minus the actual values) is executed over and over.</p>
<p>Consider the following series of queries:</p>
<div class="highlight">
<pre><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">100</span> <span class="k">AND</span> <span class="mi">499</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">500</span> <span class="k">AND</span> <span class="mi">999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">1000</span> <span class="k">AND</span> <span class="mi">1999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">2000</span> <span class="k">AND</span> <span class="mi">4999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">5000</span> <span class="k">AND</span> <span class="mi">9999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">10000</span> <span class="k">AND</span> <span class="mi">50000</span><span class="p">;</span></pre>
</div>
<p>These each represent the same query and can be transformed into a single parameterized query:</p>
<div class="highlight">
<pre><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="o">?</span> <span class="k">AND</span> <span class="o">?</span><span class="p">;</span></pre>
</div>
<p>Trying to use clever tricks with quotes in order to inject arbitrary SQL code becomes futile. Parameters are considered values, and have no effect on the structure of the query itself.</p>
<p>Parameterized queries are therefore efficient and go a long way towards preventing SQL injection attacks in your applications. They have virtually no downside.</p>
<p>Newbie developers often ignore the existence of this feature and end up irritating seasoned DBAs who have to deal with the consequences of their incompetence. <a href="http://freedb2.com/2009/09/08/the-article-every-dba-should-forward-to-sql-developers/">Leon Katsnelson argues</a> that this is such an important matter, that every DBA should forward <a href="http://www.computerworld.com/s/article/9137478/Opinion_No_more_excuses_for_SQL_injection_attacks">this Computerworld article</a> to their developers. I tend to agree with how important of an issue that is.</p>
<p>That article provides the following example in Java:</p>
<div class="highlight">
<pre><span class="n">String</span> <span class="n">lastName</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getParameter</span><span class="o">(</span><span class="s">"lastName"</span><span class="o">);</span>
<span class="n">String</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"select * from customers where last_name = ?"</span>
<span class="n">PreparedStatement</span> <span class="n">pstmt</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="na">prepareStatement</span><span class="o">(</span><span class="n">query</span><span class="o">);</span>
<span class="n">pstmt</span><span class="o">.</span><span class="na">setString</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="n">lastName</span><span class="o">);</span>
<span class="k">try</span> <span class="o">{</span> <span class="n">ResultSet</span> <span class="n">results</span> <span class="o">=</span> <span class="n">pstmt</span><span class="o">.</span><span class="na">execute</span><span class="o">();</span> <span class="o">}</span></pre>
</div>
<p>Here I&#8217;ll show you an example of how to work with parameterized queries from Ruby and Python. I&#8217;ll use the Ruby and Python drivers for <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2</a>.</p>
<p>Ruby first:</p>
<div class="highlight">
<pre><span class="nb">require</span> <span class="s1">'ibm_db'</span>

<span class="n">conn</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">"mydb"</span><span class="p">,</span> <span class="s2">"db2inst1"</span><span class="p">,</span> <span class="s2">"mypassword"</span><span class="p">)</span>

<span class="n">query</span> <span class="o">=</span> <span class="s2">"SELECT * FROM users WHERE karma BETWEEN ? AND ?"</span>
<span class="n">pstmt</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>

<span class="n">values</span> <span class="o">=</span> <span class="o">[</span><span class="mi">500</span><span class="p">,</span> <span class="mi">999</span><span class="o">]</span>
<span class="no">IBM_DB</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">pstmt</span><span class="p">,</span> <span class="n">values</span><span class="p">)</span>

<span class="k">while</span> <span class="n">row</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="o">.</span><span class="n">fetch_array</span><span class="p">(</span><span class="n">pstmt</span><span class="p">)</span>
  <span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">row</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">row</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span></pre>
</div>
<p>We load the driver (use <code>mswin32/ibm_db</code> on Windows, and <code>ibm_db.bundle</code> on Mac), create a prepared statement, and then bind the two parameter values to it through the <code>execute</code> method. We then fetch the resultset one row at a time and print the value of the first two fields for each record. For fine-tuned control we could have used the <a href="http://rubyibm.rubyforge.org/docs/driver/0.9.0/rdoc/classes/IBM_DB.html#M000005">IBM_DB::bind_param</a> method.</p>
<p>The Python version is very similar:</p>
<div class="highlight">
<pre><span class="kn">import</span> <span class="nn">ibm_db</span>

<span class="n">conn</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s">"mydb"</span><span class="p">,</span> <span class="s">"db2inst1"</span><span class="p">,</span> <span class="s">"mypassword"</span><span class="p">)</span>

<span class="n">query</span> <span class="o">=</span> <span class="s">"SELECT * FROM users WHERE karma BETWEEN ? AND ?"</span>
<span class="n">pstmt</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>

<span class="n">values</span> <span class="o">=</span> <span class="p">(</span><span class="mf">500</span><span class="p">,</span> <span class="mf">999</span><span class="p">)</span>
<span class="n">ibm_db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">pstmt</span><span class="p">,</span> <span class="n">values</span><span class="p">)</span>

<span class="nb">tuple</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">fetch_tuple</span><span class="p">(</span><span class="n">pstmt</span><span class="p">)</span>
<span class="k">while</span> <span class="nb">tuple</span><span class="p">:</span>
    <span class="k">print</span> <span class="nb">tuple</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span> <span class="o">+</span> <span class="s">":"</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span>
    <span class="nb">tuple</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">fetch_tuple</span><span class="p">(</span><span class="n">pstmt</span><span class="p">)</span></pre>
</div>
<p>As you can see, working with parameterized queries is not any harder than dynamically generating SQL queries. Yet the benefits of doing so are huge.</p>
<p>Unfortunately, despite being a very sound choice to base an Object-Relational Mapper (ORM) on, ActiveRecord does not use parameterized queries. Even when it looks like you are passing parameters to a given method, these are actually used to dynamically form an SQL query. Of course you are still free to use parameterized queries in your Rails applications by employing the driver directly. But I really think this is something ActiveRecord should be built upon.</p>
<p>Luckily for Django developers, Django&#8217;s ORM uses parameterized queries, thus improving both performance and security with a single design choice. In the Python world you couldn&#8217;t get away with ignoring parameterized queries.</p>
<p>For those of you using Rails, all is not lost. <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2 Express-C 9.7</a> has a killer feature known as the <a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.db2.luw.wn.doc/doc/c0054005.html">Statement Concentrator</a>, which caches similar queries allowing them to use a shared access plan. It&#8217;s not as efficient as using prepared statements in your code, but it&#8217;s the best you can do when, as in the case of ActiveRecord, you can&#8217;t use parameterized queries directly. <a href="http://freedb2.com/2009/09/08/the-article-every-dba-should-forward-to-sql-developers/">Leon&#8217;s article</a> explains in greater detail how this feature actually works.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/09/09/improve-the-speed-and-security-of-your-sql-queries/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Enabling support for DB2 and Python/Django/SQLAlchemy on Mac OS X Snow Leopard</title>
		<link>http://programmingzen.com/2009/09/08/enabling-support-for-db2-and-pythondjangosqlalchemy-on-mac-os-x-snow-leopard/</link>
		<comments>http://programmingzen.com/2009/09/08/enabling-support-for-db2-and-pythondjangosqlalchemy-on-mac-os-x-snow-leopard/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 23:39:34 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1099</guid>
		<description><![CDATA[This article is obsolete. Please refer to the following articles for up do date instructions: Ruby/Rails and DB2 &#124; Python/Django and DB2. Thank you! This is the Python version of a post I made about Ruby a few days ago. Now that Mac OS X 10.6 is out, it’s time to leave the world of [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p></p>
<p style="font-size: 16px; padding: 10px; border: 3px solid #ff8833; text-align: center;">This article is obsolete. Please refer to the following articles for up do date instructions: <a href="/ruby-rails-db2">Ruby/Rails and DB2</a> | <a href="/python-django-db2">Python/Django and DB2</a>. Thank you!</p>
<p><em>This is the Python version of </em><a href="http://antoniocangiano.com/2009/09/03/installing-the-ruby-driver-for-db2-on-mac-os-x-snow-leopard/"><em>a post I made about Ruby</em></a><em> a few days ago.</em></p>
<p>Now that Mac OS X 10.6 is out, it’s time to leave the world of 32 bit computing behind. The pre-installed Python interpreter will run in 64 bit mode by default, so you may need to pay attention when installing some C-based eggs.</p>
<p>Assuming you have <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2 Express-C</a> installed already, the ibm_db Python egg for DB2 can easily be installed by following these simple steps:</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo -s
<span class="nv">$ </span><span class="nb">export </span><span class="nv">IBM_DB_LIB</span><span class="o">=</span>/Users/&lt;username&gt;/sqllib/lib64
<span class="nv">$ </span><span class="nb">export </span><span class="nv">IBM_DB_DIR</span><span class="o">=</span>/Users/&lt;username&gt;/sqllib
<span class="nv">$ </span><span class="nb">export </span><span class="nv">ARCHFLAGS</span><span class="o">=</span><span class="s2">"-arch x86_64"</span>
<span class="nv">$ </span>easy_install ibm_db</pre>
</div>
<p>This will install the ibm_db C driver, and the ibm_db_dbi Python module that complies to the DB-API 2.0 specification.</p>
<p>You can verify that the installation was successful my running the following:</p>
<div class="highlight">
<pre><span class="nv">$ </span>python
<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">ibm_db</span>
<span class="o">&gt;&gt;&gt;</span></pre>
</div>
<p>Now, for the Django adapter, install Django first (if you haven&#8217;t done so already):</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo easy_install django</pre>
</div>
<p>The Django adapter can then be installed as follows:</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo easy_install ibm_db_django</pre>
</div>
<p>Finally, if have installed SQLAlchemy and wish to install the DB2 adapter for it, run:</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo easy_install ibm_db_sa</pre>
</div>
<p>Please let me know if you encounter any issues, I’d be glad to help you.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/09/08/enabling-support-for-db2-and-pythondjangosqlalchemy-on-mac-os-x-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Startup for sale on eBay (and it&#8217;s a great deal)</title>
		<link>http://programmingzen.com/2009/08/31/startup-for-sale-on-ebay-a-great-deal/</link>
		<comments>http://programmingzen.com/2009/08/31/startup-for-sale-on-ebay-a-great-deal/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 14:59:32 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Startup]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1092</guid>
		<description><![CDATA[One of the best programmers I know is selling a web application on eBay, that he&#8217;s been developing and running for the past three years. Given the starting price and considering what one lucky person or company will walk away with, I must say, it&#8217;s an amazing deal. I&#8217;m writing about his auction here so [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>One of the best programmers I know is <a href="http://cgi.ebay.it/ws/eBayISAPI.dll?ViewItem&amp;item=300343155414#ht_1769wt_1167">selling a web application on eBay</a>, that he&#8217;s been developing and running for the past three years. Given the starting price and considering what one lucky person or company will walk away with, I must say, it&#8217;s an amazing deal. I&#8217;m writing about his auction here so that I can help it get the proper exposure it deserves and because I think it&#8217;s an incredible bargain for anyone who is interested!</p>
<p align="center"><img src="http://antoniocangiano.com/wp-content/uploads/2009/08/BlogBabel1.png" alt="BlogBabel on eBay" /></p>
<p><a href="http://it.blogbabel.com">BlogBabel</a>, the aforementioned site/web app, is a blog indexing and aggregation service that began in 2006. Amongst its features are the ability to detect and show the most popular blog discussions, weekly posts, <a href="http://it.blogbabel.com/content/books/">books</a>, <a href="http://it.blogbabel.com/content/videos/">videos</a>, and even popular blog entries based on their location (through geotagging). It also features <a href="http://it.blogbabel.com/metrics/">leaderboards</a> of the most popular blogs.</p>
<p>Its codebase uses Python and Django, and consists of 27,359 physical lines of code (roughly equivalent to 6.46 person-years, according to sloccount). The R&amp;D alone makes this application worthwhile to an interested party.</p>
<p>At this stage, BlogBabel has an Italian interface (located at it.blogbabel.com) and aggregates almost 15,000 Italian blogs and 5 million posts. Changing the interface to make it an international project that&#8217;s available in several languages, or switching to English (solely), would not be challenging in the least (they used to run a Spanish version as well, for example, but decided to discontinue it so as to focus on the Italian one).</p>
<p>BlogBabel has been featured in the mainstream Italian media and has had a noticeable influence on the Italian blogosphere. One could argue that it has been the yellow pages of the Italian blogosphere. Because of this, Ludovico Magnocavallo (the site&#8217;s creator) received substantial offers to buy BlogBabel in the past, but he turned them down because he wanted to continue building this site. Now however, due to personal circumstances and lack of time/resources, he&#8217;s willing to sell this application for what may amount to far less than its true value. And here&#8217;s the real bargain, the starting price, without a reserve, is 4,999 Euros. This is of course, a ridiculously low price for the value being offered. But Ludovico believes in letting the market decide.</p>
<p>If I had the funds lying around, I would buy it myself and gear it towards the English speaking world (in conjunction with the pre-existing Italian version). It&#8217;s a prepackaged, virtually ready-made startup with a great deal of potential both in its current state and in terms of what it could grow to become.</p>
<p>To recap, the auction includes:</p>
<ul>
<li> The domain name blogbabel.com (it.blogbabel.com has a pagerank of 6);</li>
<li>The full codebase (almost 30,000 lines of code);</li>
<li>A database containing 3 years worth of data relating to the Italian blogosphere (more than 30 GB, lots of data-mining opportunities);</li>
<li>4 hours of work to help you with setting up the site on your own servers.</li>
</ul>
<p>BlogBabel has been running smoothly for three years, and is currently under-marketed. Optimizing ads, affiliates, and similar sources of revenue wouldn&#8217;t be hard at all, especially if one were to aim this site at the English speaking world.</p>
<p>Also, Ludovico has already implemented most of the code that&#8217;s necessary to allow users to have accounts (through OpenID), but since these &#8220;social features&#8221; are not fully implemented yet, they have not been deployed in production. A buyer could decide to disregard them or finish implementing them and roll out a technorati-like service. The winner of this auction could decide to implement support for Twitter, comments on social networks, sentiment analysis, etc, on their own. The possibilities are really limitless when you start with a solid engine and crawler, and already have a great deal of data at your fingertips.</p>
<p>I know Ludovico and he&#8217;s a stand-up guy. If you are interested in this great deal, you can <a href="http://cgi.ebay.it/ws/eBayISAPI.dll?ViewItem&amp;item=300343155414#ht_1769wt_1167">bid here</a>. If you have technical questions about this auction, please feel free to contact him directly through eBay.</p>
<p>UPDATE (September 8, 2009): Ludovico received an undisclosed offer for the site and a few years of maintenance work, so the auction for the site alone was suspended.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/08/31/startup-for-sale-on-ebay-a-great-deal/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The DB2 adapter now supports Django 1.1</title>
		<link>http://programmingzen.com/2009/08/06/the-db2-adapter-now-supports-django-1-1/</link>
		<comments>http://programmingzen.com/2009/08/06/the-db2-adapter-now-supports-django-1-1/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 17:27:57 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1009</guid>
		<description><![CDATA[This article is obsolete. Please refer to the following articles for up do date instructions: Ruby/Rails and DB2 &#124; Python/Django and DB2. Thank you! I&#8217;m glad to announce that the API team has just released version 1.0.2 of the adapter for Django. And on my birthday to boot, what a nice present. This version extends [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p></p>
<p style="font-size: 16px; padding: 10px; border: 3px solid #ff8833; text-align: center;">This article is obsolete. Please refer to the following articles for up do date instructions: <a href="/ruby-rails-db2">Ruby/Rails and DB2</a> | <a href="/python-django-db2">Python/Django and DB2</a>. Thank you!</p>
<p>I&#8217;m glad to announce that the API team has <a href="http://groups.google.com/group/ibm_db/browse_frm/thread/98c2c700412688">just released</a> version 1.0.2 of the adapter for Django. And on my birthday to boot, what a nice present. This version extends its support to the recently released Django 1.1, as well as incorporating <a href="http://antoniocangiano.com/2009/06/19/db2-express-c-97-and-the-django-adapter-released/#comments">the feedback</a> that was received earlier on. <img src='http://programmingzen.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  (For installation instructions, take a look at the <a href="http://code.google.com/p/ibm-db/wiki/ibm_db_django_README">README file</a>.)</p>
<p>IBM confirms its commitment to support Python and Django, and gives Django well deserved credentials in environments where having IBM&#8217;s support counts. Django is becoming an increasingly mature web framework with the potential to do well within the Enterprise world. Having support for <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&#038;S_TACT=ACDB201">DB2</a> will surely help.</p>
<p>The next step will be working with the Django team to bake DB2 support directly into Django&#8217;s releases. The code for the adapter is released under a liberal OSI-compliant license that is compatible with Django&#8217;s own BSD, and the API team is more than willing to work on the development and support of the adapter should it become part of Django. We love Django and <a href="http://djangopony.com/">ponies</a>. Let&#8217;s make this happen, guys.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/08/06/the-db2-adapter-now-supports-django-1-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

