<?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>Erik&#039;s Weblog &#187; erik</title>
	<atom:link href="http://erik.labianca.org/blog/author/erik/feed/" rel="self" type="application/rss+xml" />
	<link>http://erik.labianca.org/blog</link>
	<description>A blog. About stuff.</description>
	<lastBuildDate>Tue, 28 Dec 2010 23:05:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Django PostgreSQL ORM Overhead</title>
		<link>http://erik.labianca.org/blog/2010/06/django-postgresql-orm-overhead/</link>
		<comments>http://erik.labianca.org/blog/2010/06/django-postgresql-orm-overhead/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 00:15:12 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://erik.labianca.org/blog/?p=135</guid>
		<description><![CDATA[This is another post I&#8217;ve been sitting on for the better part of a year. I&#8217;m putting it out there in case the raw numbers are useful to anybody. So I&#8217;ve been dealing with some database performance issues with a &#8230; <a href="http://erik.labianca.org/blog/2010/06/django-postgresql-orm-overhead/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is another post I&#8217;ve been sitting on for the better part of a year. I&#8217;m putting it out there in case the raw numbers are useful to anybody.</p>
<p>So I&#8217;ve been dealing with some database performance issues with a fairly large Django application and have been trying to track down exactly where the bottlenecks are. Interestingly, neither the application servers nor the database server displays high cpu utilization, so something is locking outside of pure CPU.</p>
<p>All tests were run on an AWS EC2 image, running CentOS 5.3, Python 2.6 and the PGDG PostgreSQL83 RPM packages. The database server is an identical AWS image running PGDG postgresql83.</p>
<p>The quick takeaways from all this are the following:</p>
<ol>
<li>PostgreSQL singleton selects are pretty fast</li>
<li>The libpq library imposes more overhead than the database server does</li>
<li>For the trivial case of an application that uses PostgreSQL as a key-value store containing a working set less than 1/2 the system RAM, you&#8217;ll need many application servers to saturate it. No, I don&#8217;t know how many, but it doesn&#8217;t really matter because for a non-trivial application the PostgreSQL client library overhead will become negligible.</li>
<li>The Django ORM and psycopg2 drivers add approximately 50% overhead vs. pure c+libpq program.</li>
<li>There are some interesting bottlenecks out there that will prevent CPU saturation of a trivial workload. No, I do not know what they are (yet).</li>
<li>PgBouncer adds a bit of overhead to maximum throughput, around 5% in this case.</li>
<li>Local connections are faster than network connections. Add this to the fact there seem to be some wierd bottlenecks and you might find that your app runs faster on 1 server than 2. Interesting.</li>
</ol>
<p>I put together some very simple tests to try to figure out what&#8217;s going on.</p>
<p>First, the &#8220;Django&#8221; program:<br />
<code><br />
#!/usr/bin/python26<br />
from pprint import pprint<br />
import sys<br />
import os</code></p>
<p><span style="font-family: monospace;">from django.core.management import execute_manager</span></p>
<p><code>try:<br />
import local_settings<br />
except ImportError:<br />
import sys<br />
sys.stderr.write("Unable to find settings file")<br />
sys.exit(1)</p>
<p>from django.contrib.sites.models import Site</p>
<p>def stest():<br />
s = Site.objects.get(domain = 'example.com')</p>
<p></code></p>
<p><code>if __name__ == '__main__':<br />
from timeit import Timer<br />
s = Timer(stmt=stest)<br />
print 'different query 1'<br />
print s.timeit(number=1)<br />
print 'different query 2'<br />
print s.timeit(number=1)<br />
print 'different query 10 more'<br />
print s.timeit(number=1000000)<br />
</code></p>
<p>The C program:<br />
<code><br />
/*<br />
* testlibpq.c<br />
*<br />
*      Test the C version of libpq, the PostgreSQL frontend library.<br />
*/<br />
#include<br />
#include<br />
#include "libpq-fe.h"</code></p>
<p><code> </code></p>
<p><code>static void<br />
exit_nicely(PGconn *conn)<br />
{<br />
PQfinish(conn);<br />
exit(1);<br />
}</p>
<p>int<br />
main(int argc, char **argv)<br />
{<br />
const char *conninfo;<br />
PGconn     *conn;<br />
PGresult   *res;<br />
int         nFields;<br />
int         count,<br />
i,<br />
j;</p>
<p>/*<br />
* If the user supplies a parameter on the command line, use it as the<br />
* conninfo string; otherwise default to setting dbname=postgres and using<br />
* environment variables or defaults for all other connection parameters.<br />
*/<br />
if (argc &gt; 1)<br />
conninfo = argv[1];<br />
else<br />
conninfo = "dbname = ngdm_wpf_content";</p>
<p>/* Make a connection to the database */<br />
conn = PQconnectdb(conninfo);</p>
<p>/* Check to see that the backend connection was successfully made */<br />
if (PQstatus(conn) != CONNECTION_OK)<br />
{<br />
fprintf(stderr, "Connection to database failed: %s",<br />
PQerrorMessage(conn));<br />
exit_nicely(conn);<br />
}</p>
<p>/*<br />
* Our test case here involves using a cursor, for which we must be inside<br />
* a transaction block.  We could do the whole thing with a single<br />
* PQexec() of "select * from pg_database", but that's too trivial to make<br />
* a good example.<br />
*/</p>
<p>for ( count=0; count &lt; 100; count++) {<br />
/* Start a transaction block */<br />
res = PQexec(conn, "SELECT * FROM django_site WHERE django_site.domain = 'example.com' ORDER BY django_site.domain;");<br />
if (PQresultStatus(res) != PGRES_TUPLES_OK)<br />
{<br />
fprintf(stderr, "SELECT command failed (%d): %s", PQresultStatus(res), PQerrorMessage(conn));<br />
PQclear(res);<br />
exit_nicely(conn);<br />
}</p>
<p>PQclear(res);</p>
<p>}</p>
<p>/* close the connection to the database and cleanup */<br />
PQfinish(conn);</p>
<p></code></p>
<p><code> return 0;<br />
}<br />
</code></p>
<p><code><br />
gcc -o bench -lpq bench.c<br />
time  ./bench "dbname=content hostaddr=127.0.0.1 user=user"<br />
</code></p>
<p>Running 8 concurrent python programs, via pgbouncer, client:</p>
<pre>top - 22:05:16 up  3:50,  5 users,  load average: 3.94, 3.42, 2.45
Tasks: 135 total,   4 running, 131 sleeping,   0 stopped,   0 zombie
Cpu(s): 12.3%us,  1.0%sy,  0.0%ni, 84.2%id,  0.0%wa,  0.0%hi,  0.8%si,  1.7%st
Mem:   7347752k total,  5608152k used,  1739600k free,    70732k buffers
Swap:        0k total,        0k used,        0k free,   452504k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 3124 root      15   0  762m 623m 4976 S   40  8.7   5:07.23 bench.py
 3125 root      15   0  722m 583m 4976 S   14  8.1   4:15.34 bench.py
 3122 root      15   0  701m 562m 4976 S   14  7.8   3:29.58 bench.py
 2523 postgres  15   0 17092 1240  792 S   10  0.0   3:31.90 pgbouncer
 3126 root      15   0  699m 560m 4976 R    8  7.8   3:10.76 bench.py
 3121 root      15   0  822m 683m 4976 S    8  9.5   6:03.10 bench.py
 3123 root      15   0  700m 561m 4976 R    7  7.8   2:47.05 bench.py
 3128 root      15   0  700m 561m 4976 S    7  7.8   3:23.07 bench.py
 3127 root      15   0  714m 575m 4976 R    6  8.0   4:52.92 bench.py</pre>
<p>And the server:</p>
<pre>top - 21:39:50 up  6:36,  4 users,  load average: 7.44, 3.44, 1.49
Tasks: 142 total,  11 running, 131 sleeping,   0 stopped,   0 zombie
top - 22:06:04 up  7:02,  4 users,  load average: 3.15, 3.19, 4.10
Tasks: 127 total,   4 running, 123 sleeping,   0 stopped,   0 zombie
Cpu(s):  2.2%us,  1.3%sy,  0.0%ni, 95.5%id,  0.4%wa,  0.0%hi,  0.3%si,  0.3%st
Mem:   7347752k total,  2313112k used,  5034640k free,     4124k buffers
Swap:        0k total,        0k used,        0k free,  1996524k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 6910 postgres  15   0 2160m 5748 3888 S    6  0.1   1:15.31 postmaster
 6902 postgres  15   0 2160m 5740 3880 S    5  0.1   1:17.22 postmaster
 6913 postgres  15   0 2160m 5748 3888 R    4  0.1   1:08.97 postmaster
 6911 postgres  15   0 2160m 5748 3888 S    3  0.1   1:08.78 postmaster
 6912 postgres  15   0 2160m 5756 3896 S    3  0.1   1:07.76 postmaster
 6908 postgres  15   0 2160m 5740 3880 S    3  0.1   1:05.38 postmaster
 6909 postgres  15   0 2160m 5748 3888 S    3  0.1   1:05.88 postmaster
 6917 postgres  15   0 2160m 5748 3888 R    3  0.1   1:06.88 postmaster</pre>
<p>Running the the Django benchmark with 10,000 iterations via pgbouncer demonstrates a 300ms startup time, and a sustained trivial query rate of almost exactly 1000/sec:</p>
<pre>[root@domU-12-31-38-04-59-91 ~]# time ./bench.py
initial
0.306927919388
second
0.00195598602295
10 more
0.0144731998444
different query 1
0.00151586532593
different query 2
0.00109100341797
different query 10 more
9.89285588264

real    0m10.650s
user    0m4.217s
sys     0m0.229s</pre>
<p>Exactly the same test, without pgbouncer, results in approximately 5% improvement in throughput:</p>
<pre>[root@domU-12-31-38-04-59-91 ~]# time ./bench.py
initial
0.304031133652
second
0.00196003913879
10 more
0.0196559429169
different query 1
0.00163292884827
different query 2
0.000943899154663
different query 10 more
9.48121595383

real    0m10.238s
user    0m4.188s
sys     0m0.219s</pre>
<p>And finally, running it directly on the database server knocks off almost 30%:</p>
<pre>[root@domU-12-31-38-04-58-E1 data]# time ./bench.py
initial
0.651133060455
second
0.00181007385254
10 more
0.0109980106354
different query 1
0.00134086608887
different query 2
0.000818014144897
different query 10 more
6.95133709908

real    0m9.535s
user    0m5.814s
sys     0m0.275s</pre>
<p>And now,running 10,000 queries via the c program:</p>
<pre>[root@domU-12-31-38-04-59-91 ~]# time ./bench "dbname=content hostaddr=127.0.0.1 user=user"

real    0m4.648s
user    0m0.003s
sys     0m0.031s</pre>
<p>And via pgbouncer:</p>
<pre>[root@domU-12-31-38-04-59-91 ~]# time ./bench "dbname=content hostaddr=10.220.91.15 user=user"

real    0m3.799s
user    0m0.004s
sys     0m0.005s</pre>
<p>And directly on the server:</p>
<pre>[root@domU-12-31-38-04-58-E1 tmp]#  time ./bench "dbname=ngdm_wpf_content hostaddr=127.0.0.1 user=ngdm_wpf"

real    0m1.758s
user    0m0.048s
sys     0m0.062s</pre>
<p>Now, let&#8217;s try to melt things down:<br />
8 clients via pgbouncer:</p>
<p>8 clients directly</p>
<p>8 C clients with pgbouncer, client load:<br />
top &#8211; 22:23:49 up  4:08,  5 users,  load average: 1.36, 0.50, 0.94<br />
Tasks: 148 total,   3 running, 144 sleeping,   1 stopped,   0 zombie<br />
Cpu(s):  1.1%us,  4.4%sy,  0.0%ni, 91.5%id,  0.0%wa,  0.0%hi,  2.4%si,  0.6%st<br />
Mem:   7347752k total,   822812k used,  6524940k free,    72052k buffers<br />
Swap:        0k total,        0k used,        0k free,   452656k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
2523 postgres  15   0 17092 1240  792 R   50  0.0   4:10.58 pgbouncer<br />
3771 root      15   0 48840 1884 1464 S    6  0.0   0:00.70 bench<br />
3765 root      15   0 48836 1888 1464 S    3  0.0   0:00.72 bench<br />
3761 root      15   0 48836 1888 1464 R    1  0.0   0:01.86 bench<br />
3773 root      15   0 48836 1884 1464 S    1  0.0   0:00.21 bench<br />
3780 root      15   0 48836 1884 1464 S    1  0.0   0:00.11 bench<br />
3759 root      15   0 48836 1884 1464 S    0  0.0   0:00.25 bench<br />
3763 root      15   0 48840 1888 1464 S    0  0.0   0:00.19 bench</p>
<p>8 C clients, server load:<br />
top &#8211; 22:23:35 up  7:19,  4 users,  load average: 2.52, 0.79, 1.58<br />
Tasks: 129 total,   9 running, 120 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 18.9%us,  7.0%sy,  0.0%ni, 71.8%id,  0.0%wa,  0.0%hi,  2.1%si,  0.3%st<br />
Mem:   7347752k total,  2466176k used,  4881576k free,     6736k buffers<br />
Swap:        0k total,        0k used,        0k free,  2143620k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
7148 postgres  15   0 2160m 4920 3240 R   23  0.1   0:10.94 postmaster<br />
7152 postgres  15   0 2160m 4916 3236 R   21  0.1   0:08.88 postmaster<br />
7150 postgres  15   0 2160m 4916 3236 S   20  0.1   0:08.65 postmaster<br />
7147 postgres  15   0 2160m 4916 3236 S   20  0.1   0:11.63 postmaster<br />
7155 postgres  15   0 2160m 4916 3236 R   20  0.1   0:03.98 postmaster<br />
7151 postgres  15   0 2160m 4916 3236 R   19  0.1   0:08.14 postmaster<br />
7154 postgres  15   0 2160m 4920 3240 S   19  0.1   0:04.05 postmaster<br />
7145 postgres  15   0 2160m 4916 3236 R   18  0.1   0:11.57 postmaster<br />
7144 postgres  15   0 2160m 4912 3232 R   17  0.1   0:12.08 postmaster<br />
6435 postgres  15   0 60920 1012  320 S   15  0.0   3:32.23 postmaster</p>
<p>And 8 C clients, eliminating pgbouncer, client load:<br />
top &#8211; 22:25:55 up  4:10,  5 users,  load average: 0.76, 0.64, 0.94<br />
Tasks: 136 total,   2 running, 133 sleeping,   1 stopped,   0 zombie<br />
Cpu(s):  0.6%us,  1.3%sy,  0.0%ni, 97.6%id,  0.0%wa,  0.0%hi,  0.2%si,  0.3%st<br />
Mem:   7347752k total,   821436k used,  6526316k free,    72184k buffers<br />
Swap:        0k total,        0k used,        0k free,   452656k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
3791 root      15   0 48840 1888 1464 R    3  0.0   0:00.88 bench<br />
3784 root      15   0 48836 1884 1464 S    3  0.0   0:00.83 bench<br />
3788 root      15   0 48836 1884 1464 S    3  0.0   0:00.89 bench<br />
3790 root      15   0 48836 1884 1464 S    3  0.0   0:00.88 bench<br />
3785 root      15   0 48836 1884 1464 S    2  0.0   0:00.82 bench<br />
3789 root      15   0 48836 1884 1464 S    2  0.0   0:00.88 bench<br />
3787 root      15   0 48840 1888 1464 S    2  0.0   0:00.97 bench<br />
3786 root      15   0 48840 1888 1464 S    1  0.0   0:00.68 bench</p>
<p>Server load:<br />
Tasks: 132 total,   5 running, 127 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 16.5%us,  7.0%sy,  0.0%ni, 74.2%id,  0.0%wa,  0.0%hi,  1.5%si,  0.7%st<br />
Mem:   7347752k total,  2726576k used,  4621176k free,     7340k buffers<br />
Swap:        0k total,        0k used,        0k free,  2392360k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
7165 postgres  15   0 2160m 4916 3236 S   27  0.1   0:11.50 postmaster<br />
7166 postgres  15   0 2160m 4916 3236 R   26  0.1   0:11.05 postmaster<br />
7171 postgres  15   0 2160m 4916 3236 S   25  0.1   0:10.56 postmaster<br />
7164 postgres  15   0 2160m 4916 3236 S   24  0.1   0:11.62 postmaster<br />
7169 postgres  15   0 2160m 4920 3240 R   24  0.1   0:10.86 postmaster<br />
7170 postgres  15   0 2160m 4916 3236 S   23  0.1   0:10.66 postmaster<br />
7168 postgres  15   0 2160m 4916 3236 R   21  0.1   0:10.69 postmaster<br />
7167 postgres  15   0 2160m 4916 3236 R   18  0.1   0:10.72 postmaster</p>
<p>16 c clients, no pgbouncer:<br />
top &#8211; 22:28:21 up  4:13,  5 users,  load average: 1.06, 0.80, 0.95<br />
Tasks: 144 total,   2 running, 141 sleeping,   1 stopped,   0 zombie<br />
Cpu(s):  1.1%us,  3.0%sy,  0.0%ni, 94.8%id,  0.0%wa,  0.0%hi,  0.9%si,  0.3%st<br />
Mem:   7347752k total,   824680k used,  6523072k free,    72344k buffers<br />
Swap:        0k total,        0k used,        0k free,   452660k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
3785 root      15   0 48836 1884 1464 S    5  0.0   0:04.30 bench<br />
3788 root      15   0 48836 1884 1464 S    4  0.0   0:04.58 bench<br />
3798 root      15   0 48840 1888 1464 S    4  0.0   0:01.40 bench<br />
3799 root      15   0 48836 1884 1464 S    4  0.0   0:01.38 bench<br />
3784 root      15   0 48836 1884 1464 S    3  0.0   0:04.16 bench<br />
3794 root      15   0 48840 1888 1464 S    3  0.0   0:01.35 bench<br />
3787 root      15   0 48840 1888 1464 R    3  0.0   0:04.73 bench<br />
3790 root      15   0 48836 1884 1464 S    3  0.0   0:04.25 bench<br />
3789 root      15   0 48836 1884 1464 S    3  0.0   0:04.27 bench<br />
3795 root      15   0 48840 1888 1464 S    3  0.0   0:01.07 bench<br />
3786 root      15   0 48840 1888 1464 S    2  0.0   0:03.88 bench<br />
3800 root      15   0 48836 1884 1464 S    2  0.0   0:01.19 bench<br />
3793 root      15   0 48840 1888 1464 S    2  0.0   0:01.40 bench<br />
3796 root      15   0 48840 1888 1464 S    2  0.0   0:01.13 bench<br />
3791 root      15   0 48840 1888 1464 S    1  0.0   0:04.29 bench</p>
<p>16 c clients, no pgbouncer, server load:<br />
top &#8211; 22:28:28 up  7:24,  4 users,  load average: 6.68, 3.73, 2.57<br />
Tasks: 138 total,  10 running, 128 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 23.5%us,  9.6%sy,  0.0%ni, 63.7%id,  0.4%wa,  0.0%hi,  2.2%si,  0.7%st<br />
Mem:   7347752k total,  3111620k used,  4236132k free,     8060k buffers<br />
Swap:        0k total,        0k used,        0k free,  2756304k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
6435 postgres  16   0 60920 1012  320 R   27  0.0   4:17.22 postmaster<br />
7168 postgres  15   0 2160m 4920 3240 S   20  0.1   0:40.52 postmaster<br />
7296 postgres  15   0 2160m 4928 3240 R   20  0.1   0:08.51 postmaster<br />
7292 postgres  15   0 2160m 4924 3240 S   19  0.1   0:08.49 postmaster<br />
7166 postgres  15   0 2160m 4920 3240 S   19  0.1   0:41.11 postmaster<br />
7290 postgres  15   0 2160m 4924 3244 S   19  0.1   0:08.41 postmaster<br />
7295 postgres  15   0 2160m 4924 3240 S   19  0.1   0:08.21 postmaster<br />
7170 postgres  15   0 2160m 4920 3240 R   18  0.1   0:40.96 postmaster<br />
7169 postgres  15   0 2160m 4924 3244 S   18  0.1   0:40.23 postmaster<br />
7171 postgres  15   0 2160m 4920 3240 R   18  0.1   0:40.17 postmaster<br />
7167 postgres  15   0 2160m 4920 3240 S   17  0.1   0:40.05 postmaster<br />
7293 postgres  15   0 2160m 4924 3240 R   17  0.1   0:08.74 postmaster<br />
7297 postgres  15   0 2160m 4936 3248 R   16  0.1   0:07.92 postmaster<br />
7165 postgres  16   0 2160m 4920 3240 R   15  0.1   0:41.41 postmaster<br />
7291 postgres  15   0 2160m 4924 3240 R   15  0.1   0:08.61 postmaster<br />
7294 postgres  15   0 2160m 4924 3240 S   14  0.1   0:08.13 postmaster<br />
7164 postgres  15   0 2160m 4920 3240 R   13  0.1   0:41.61 postmaster<br />
6440 postgres  15   0 61468 1444  444 S    0  0.0   0:00.17 postmaster</p>
<p>4 local c processes:<br />
top &#8211; 22:31:31 up  7:27,  4 users,  load average: 4.52, 4.18, 2.97<br />
Tasks: 130 total,   7 running, 123 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 33.5%us, 15.4%sy,  0.0%ni, 48.5%id,  1.0%wa,  0.0%hi,  0.0%si,  1.5%st<br />
Mem:   7347752k total,  3594636k used,  3753116k free,     9000k buffers<br />
Swap:        0k total,        0k used,        0k free,  3239112k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
7324 postgres  25   0 2160m 4888 3208 R   84  0.1   0:51.21 postmaster<br />
7328 postgres  25   0 2160m 4888 3208 R   81  0.1   0:51.21 postmaster<br />
7326 postgres  25   0 2160m 4888 3208 R   81  0.1   0:53.49 postmaster<br />
7322 postgres  25   0 2160m 4888 3208 R   78  0.1   1:03.22 postmaster<br />
6435 postgres  15   0 60920 1012  320 R   23  0.0   4:50.81 postmaster<br />
7321 root      15   0 48836 1864 1444 S   14  0.0   0:08.83 bench<br />
7325 root      15   0 48840 1868 1444 S   11  0.0   0:07.32 bench<br />
7327 root      15   0 48840 1864 1444 S   11  0.0   0:06.04 bench<br />
7323 root      15   0 48836 1864 1444 R    9  0.0   0:05.58 bench</p>
<p>8 local processes:<br />
top &#8211; 22:32:25 up  7:28,  4 users,  load average: 6.16, 4.62, 3.18<br />
Tasks: 138 total,   6 running, 132 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 25.9%us, 16.0%sy,  0.0%ni, 55.0%id,  1.6%wa,  0.0%hi,  0.0%si,  1.5%st<br />
Mem:   7347752k total,  3821680k used,  3526072k free,     9352k buffers<br />
Swap:        0k total,        0k used,        0k free,  3451556k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
6435 postgres  16   0 60920 1012  320 R   43  0.0   5:09.25 postmaster<br />
7339 postgres  15   0 2160m 4892 3212 D   39  0.1   0:06.23 postmaster<br />
7328 postgres  25   0 2160m 4888 3208 R   34  0.1   1:24.86 postmaster<br />
7324 postgres  25   0 2160m 4888 3208 D   33  0.1   1:24.64 postmaster<br />
7326 postgres  25   0 2160m 4888 3208 D   32  0.1   1:26.53 postmaster<br />
7322 postgres  25   0 2160m 4888 3208 D   30  0.1   1:34.39 postmaster<br />
7337 postgres  16   0 2160m 4888 3208 R   28  0.1   0:06.02 postmaster<br />
7343 postgres  16   0 2160m 4888 3208 R   28  0.1   0:05.04 postmaster<br />
7341 postgres  15   0 2160m 4888 3208 S   27  0.1   0:05.56 postmaster<br />
7338 root      15   0 48840 1864 1444 S    7  0.0   0:01.05 bench<br />
7325 root      15   0 48840 1868 1444 S    6  0.0   0:12.12 bench<br />
7342 root      15   0 48836 1868 1444 S    6  0.0   0:01.02 bench<br />
7321 root      15   0 48836 1864 1444 S    6  0.0   0:11.73 bench<br />
7340 root      15   0 48836 1864 1444 R    5  0.0   0:00.77 bench<br />
7323 root      15   0 48836 1864 1444 S    4  0.0   0:10.10 bench<br />
7327 root      15   0 48840 1864 1444 S    4  0.0   0:10.24 bench<br />
7336 root      15   0 48836 1864 1444 S    3  0.0   0:00.76 bench</p>
<p>16 local processes:<br />
top &#8211; 22:33:11 up  7:29,  4 users,  load average: 10.49, 5.91, 3.69<br />
Tasks: 154 total,   9 running, 145 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 20.8%us,  9.3%sy,  0.0%ni, 59.7%id,  1.0%wa,  0.0%hi,  0.0%si,  9.1%st<br />
Mem:   7347752k total,  4032604k used,  3315148k free,     9660k buffers<br />
Swap:        0k total,        0k used,        0k free,  3639952k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
7347 postgres  15   0 2160m 4892 3212 D   17  0.1   0:02.80 postmaster<br />
7328 postgres  15   0 2160m 4888 3208 D   15  0.1   1:35.36 postmaster<br />
6435 postgres  15   0 60920 1012  320 S   15  0.0   5:22.28 postmaster<br />
7357 postgres  16   0 2160m 4892 3208 D   14  0.1   0:02.46 postmaster<br />
7359 postgres  16   0 2160m 4892 3208 R   14  0.1   0:02.46 postmaster<br />
7361 postgres  15   0 2160m 4900 3212 D   13  0.1   0:02.37 postmaster<br />
7343 postgres  16   0 2160m 4888 3208 R   13  0.1   0:16.00 postmaster<br />
7353 postgres  16   0 2160m 4892 3208 D   12  0.1   0:02.47 postmaster<br />
7322 postgres  16   0 2160m 4888 3208 R   12  0.1   1:45.13 postmaster<br />
7326 postgres  16   0 2160m 4888 3208 R   12  0.1   1:37.69 postmaster<br />
7339 postgres  15   0 2160m 4892 3212 D   12  0.1   0:16.68 postmaster<br />
7349 postgres  15   0 2160m 4892 3208 D   12  0.1   0:02.52 postmaster<br />
7324 postgres  16   0 2160m 4888 3208 D   11  0.1   1:34.90 postmaster<br />
7355 postgres  16   0 2160m 4892 3208 R   11  0.1   0:02.41 postmaster<br />
7341 postgres  16   0 2160m 4888 3208 D   11  0.1   0:16.48 postmaster<br />
7351 postgres  16   0 2160m 4892 3208 R   10  0.1   0:02.36 postmaster<br />
7337 postgres  15   0 2160m 4888 3208 D    9  0.1   0:15.76 postmaster<br />
7348 root      15   0 48840 1864 1444 S    3  0.0   0:00.42 bench<br />
7338 root      15   0 48840 1864 1444 S    3  0.0   0:02.80 bench<br />
7325 root      15   0 48840 1868 1444 R    2  0.0   0:13.61 bench<br />
7342 root      15   0 48836 1868 1444 S    2  0.0   0:02.64 bench<br />
7356 root      15   0 48840 1868 1444 S    2  0.0   0:00.31 bench<br />
7358 root      15   0 48836 1868 1444 S    2  0.0   0:00.39 bench<br />
7346 root      15   0 48840 1868 1444 S    2  0.0   0:00.43 bench<br />
7350 root      15   0 48840 1864 1444 S    2  0.0   0:00.38 bench<br />
7327 root      15   0 48840 1864 1444 S    2  0.0   0:11.59 bench<br />
7336 root      15   0 48836 1864 1444 S    2  0.0   0:02.33 bench<br />
7340 root      15   0 48836 1864 1444 S    2  0.0   0:02.51 bench<br />
7321 root      15   0 48836 1864 1444 S    1  0.0   0:13.01 bench<br />
7323 root      15   0 48836 1864 1444 S    1  0.0   0:11.48 bench<br />
7354 root      15   0 48836 1868 1444 S    1  0.0   0:00.24 bench<br />
7360 root      15   0 48840 1864 1444 S    1  0.0   0:00.33 bench</p>
<p>32 local processes:<br />
top &#8211; 22:34:50 up  7:31,  4 users,  load average: 23.32, 11.03, 5.69<br />
Tasks: 181 total,   4 running, 177 sleeping,   0 stopped,   0 zombie<br />
Cpu(s): 18.1%us,  7.2%sy,  0.0%ni, 66.6%id,  1.4%wa,  0.0%hi,  0.0%si,  6.7%st<br />
Mem:   7347752k total,  4381808k used,  2965944k free,    10244k buffers<br />
Swap:        0k total,        0k used,        0k free,  3952404k cached</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
6435 postgres  16   0 60920 1012  320 S    9  0.0   5:33.12 postmaster<br />
7347 postgres  16   0 2160m 4904 3224 D    8  0.1   0:10.34 postmaster<br />
7353 postgres  16   0 2160m 4904 3220 D    8  0.1   0:09.48 postmaster<br />
7349 postgres  16   0 2160m 4904 3220 D    8  0.1   0:10.25 postmaster<br />
7375 postgres  15   0 2160m 4908 3220 D    8  0.1   0:03.45 postmaster<br />
7326 postgres  16   0 2160m 4900 3220 D    7  0.1   1:45.29 postmaster<br />
7373 postgres  16   0 2160m 4908 3220 D    7  0.1   0:03.65 postmaster<br />
7383 postgres  16   0 2160m 4908 3220 D    7  0.1   0:03.06 postmaster<br />
7391 postgres  15   0 2160m 4912 3224 D    7  0.1   0:03.02 postmaster<br />
7324 postgres  16   0 2160m 4900 3220 D    7  0.1   1:41.96 postmaster<br />
7369 postgres  16   0 2160m 4908 3220 R    6  0.1   0:03.81 postmaster<br />
7385 postgres  16   0 2160m 4912 3224 D    6  0.1   0:02.90 postmaster<br />
7361 postgres  16   0 2160m 4912 3224 D    5  0.1   0:10.54 postmaster<br />
7379 postgres  16   0 2160m 4912 3224 D    5  0.1   0:03.40 postmaster<br />
7393 postgres  16   0 2160m 4908 3220 D    5  0.1   0:02.84 postmaster<br />
7395 postgres  16   0 2160m 4912 3224 D    5  0.1   0:03.15 postmaster<br />
7397 postgres  16   0 2160m 4912 3224 R    5  0.1   0:03.12 postmaster<br />
7343 postgres  16   0 2160m 4900 3220 D    5  0.1   0:23.27 postmaster<br />
7328 postgres  16   0 2160m 4900 3220 D    5  0.1   1:42.52 postmaster<br />
7341 postgres  16   0 2160m 4900 3220 D    5  0.1   0:23.69 postmaster<br />
7355 postgres  16   0 2160m 4904 3220 D    5  0.1   0:09.82 postmaster<br />
7359 postgres  16   0 2160m 4904 3220 D    5  0.1   0:09.84 postmaster<br />
7381 postgres  16   0 2160m 4908 3220 D    5  0.1   0:03.22 postmaster<br />
7337 postgres  16   0 2160m 4900 3220 D    4  0.1   0:23.36 postmaster<br />
7339 postgres  16   0 2160m 4904 3224 D    4  0.1   0:24.46 postmaster<br />
7367 postgres  15   0 2160m 4908 3220 D    4  0.1   0:03.26 postmaster<br />
7357 postgres  16   0 2160m 4904 3220 D    4  0.1   0:10.21 postmaster<br />
7371 postgres  16   0 2160m 4912 3224 D    4  0.1   0:02.97 postmaster<br />
7387 postgres  16   0 2160m 4908 3220 D    4  0.1   0:02.87 postmaster<br />
7389 postgres  16   0 2160m 4908 3220 D    3  0.1   0:03.03 postmaster<br />
7377 postgres  15   0 2160m 4908 3220 D    3  0.1   0:03.03 postmaster<br />
7351 postgres  16   0 2160m 4904 3220 D    2  0.1   0:09.71 postmaster<br />
7358 root      15   0 48836 1868 1444 S    2  0.0   0:01.62 bench<br />
7325 root      15   0 48840 1868 1444 S    1  0.0   0:14.73 bench<br />
7346 root      15   0 48840 1868 1444 S    1  0.0   0:01.44 bench<br />
7352 root      15   0 48836 1864 1444 S    1  0.0   0:01.45 bench<br />
7374 root      15   0 48840 1864 1444 S    1  0.0   0:00.48 bench<br />
7323 root      15   0 48836 1864 1444 S    1  0.0   0:12.52 bench<br />
7342 root      15   0 48836 1868 1444 S    1  0.0   0:03.75 bench<br />
7366 root      15   0 48836 1868 1444 S    1  0.0   0:00.48 bench<br />
7370 root      15   0 48840 1868 1444 S    1  0.0   0:00.43 bench<br />
7378 root      15   0 48840 1868 1444 S    1  0.0   0:00.36 bench<br />
7382 root      15   0 48840 1868 1444 S    1  0.0   0:00.31 bench<br />
7388 root      15   0 48836 1864 1444 S    1  0.0   0:00.43 bench<br />
7390 root      15   0 48836 1868 1444 S    1  0.0   0:00.36 bench<br />
2455 root      18   0  247m 1580  860 S    1  0.0   0:12.46 collectd<br />
7336 root      15   0 48836 1864 1444 S    1  0.0   0:03.32 bench<br />
7348 root      15   0 48840 1864 1444 S    1  0.0   0:01.38 bench<br />
7350 root      15   0 48840 1864 1444 S    1  0.0   0:01.26 bench<br />
7354 root      15   0 48836 1868 1444 S    1  0.0   0:01.09 bench<br />
7356 root      15   0 48840 1868 1444 S    1  0.0   0:01.47 bench<br />
7368 root      15   0 48840 1864 1444 S    1  0.0   0:00.42 bench<br />
7386 root      15   0 48840 1864 1444 S    1  0.0   0:00.40 bench<br />
7392 root      15   0 48836 1868 1444 S    1  0.0   0:00.42 bench<br />
7327 root      15   0 48840 1864 1444 S    0  0.0   0:12.57 bench<br />
7340 root      15   0 48836 1864 1444 S    0  0.0   0:03.56 bench<br />
7376 root      15   0 48836 1868 1444 S    0  0.0   0:00.45 bench<br />
7380 root      15   0 48840 1864 1444 S    0  0.0   0:00.38 bench<br />
7394 root      15   0 48840 1864 1444 S    0  0.0   0:00.59 bench</p>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2010/06/django-postgresql-orm-overhead/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript QuickStart Reference</title>
		<link>http://erik.labianca.org/blog/2010/06/javascript-quickstart-reference/</link>
		<comments>http://erik.labianca.org/blog/2010/06/javascript-quickstart-reference/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 23:57:02 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Information]]></category>

		<guid isPermaLink="false">http://www.cto-at-large.com/?p=107</guid>
		<description><![CDATA[I wrote this quite some time ago when I had to re-acquiant myself with JavaScript, but never posted it. It&#8217;s not complete, but it&#8217;s got some of the basics so I&#8217;m going to go ahead and hit publish anyway. Javascript &#8230; <a href="http://erik.labianca.org/blog/2010/06/javascript-quickstart-reference/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I wrote this quite some time ago when I had to re-acquiant myself with JavaScript, but never posted it. It&#8217;s not complete, but it&#8217;s got some of the basics so I&#8217;m going to go ahead and hit publish anyway. Javascript (actually <a title="http://en.wikipedia.org/wiki/ECMAScript" href="http://en.wikipedia.org/wiki/ECMAScript" target="_blank">ECMAScript </a>nowadays)  is everywhere. If you&#8217;ve never had to use it, you&#8217;ve somehow managed to avoid writing any modern web apps. The good thing is, it&#8217;s really very simple! A few things you should know before getting started:</p>
<ol>
<li>JavaScript uses (more or less) the standard Algol (C-like) syntax, including most C programming constructs.
<pre><code>
if (myVar == True) { doMyFunction(1, 2); myVar = False; }
while (myVar == True) { doMyFunction(2,3); myVar = False; }
for ( var i = 0; i &lt; 10; i++ ) { doMyFunction(i, 2); }
switch(myVar) {
    case "A": doMyFunction(1, 3);
    case "B": doMyFunction(2, 1);
}</code></pre>
</li>
<li>In JavaScript, functions are &#8220;first-class&#8221;, simply meaning they are objects. As objects, the can be passed around and modified like any other object. This functionality is key to most JavaScript idioms, so make sure you understand it.
<pre><code>
function doMyFunction(x, y) {
    if (x % 1 != 0)
        throw new TypeError(x + " is not an integer");
  return x * y;
}

/*
 * This callback variable probably should be global to be useful!
 * You'll see this idiom a LOT with any sort of AJAX programming
 */
function setCallBack(callback) {
    var callbackVar = callback;
}
</code></pre>
</li>
<li>JavaScript itself does not provide a class library or define any runtime services. This results in JavaScript often looking more complicated than it really is because it&#8217;s always intertwined with a bunch of wierd browser runtime stuff. For instance, the following is probably the easiest way to write a &#8220;Hello World&#8221; in  JavaScript, but note that the document object is provided by the browser!
<pre><code>
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"&gt;&lt;/code&gt;
&lt;html&gt;
  &lt;head&gt;&lt;title&gt;simple page&lt;/title&gt;&lt;/head&gt;
  &lt;body&gt;
    &lt;script type="text/javascript"&gt;
      document.write('Hello World!');
    &lt;/script&gt;
    &lt;noscript&gt;
      &lt;p&gt;Your browser either does not support JavaScript, or you have JavaScript turned off.&lt;/p&gt;
    &lt;/noscript&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
</li>
<li>JavaScript array and object literals are form the basis for JavaScript Object Notation or JSON, which is commonly used as a data transport in AJAX applications. The syntax  looks like this:
<pre><code>
{
    "pos": {
        "x": 5,
        "y": 7
     },
    "name": "JavaScript",
    "numbers": [ "first", "second", "third" ]
}
</code></pre>
</li>
<li>JavaScript is a dynamic language. As a dynamic language, you get the &#8220;eval&#8221; function. Eval opens the door to everything that makes JavaScript powerful, and also most of the possible security holes. Do not eval anything unless you have complete confidence that is is trustworthy code!
<pre><code>
str = "{ "pos": { "x": 5, "y": 7 } }";
var myObj = eval(str);
alert(myObj.pos.x);
</code></pre>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2010/06/javascript-quickstart-reference/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to show hidden files in Mac OS Finder</title>
		<link>http://erik.labianca.org/blog/2009/11/how-to-show-hidden-files-in-mac-os-finder/</link>
		<comments>http://erik.labianca.org/blog/2009/11/how-to-show-hidden-files-in-mac-os-finder/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 02:26:03 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Computing]]></category>
		<category><![CDATA[Tweaks]]></category>

		<guid isPermaLink="false">http://erik.labianca.org/blog/?p=128</guid>
		<description><![CDATA[Need to see hidden files in OS X Snow Leopard Finder? Use cmd-shift-. <a href="http://erik.labianca.org/blog/2009/11/how-to-show-hidden-files-in-mac-os-finder/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m not sure why this command doesn&#8217;t get more play, so I&#8217;m gonna put it out there so google picks it up. At least in Snow Leopard, simply hitting cmd-shift-. will show hidden files for that browse session.</p>
<p><code><br />
defaults write com.apple.finder AppleShowAllFiles TRUE<br />
killall Finder<br />
</code></p>
<p>At least for me, that&#8217;s a much more usable solution than permanently showing all hidden files, which is what you get by executing the more commonly documented solution:</p>
<p>See also:<br />
[1] <a href="http://www.macworld.com/article/142884/2009/09/106seehidden.html">http://www.macworld.com/article/142884/2009/09/106seehidden.html</a><br />
[2] <a href="http://www.mactricksandtips.com/2008/04/show-hidden-files.html">http://www.mactricksandtips.com/2008/04/show-hidden-files.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/11/how-to-show-hidden-files-in-mac-os-finder/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Blog re-integration complete</title>
		<link>http://erik.labianca.org/blog/2009/09/blog-re-integration-complete/</link>
		<comments>http://erik.labianca.org/blog/2009/09/blog-re-integration-complete/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 20:51:26 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://erik.labianca.org/blog/?p=122</guid>
		<description><![CDATA[I&#8217;ve merged my two blogs back into one since I haven&#8217;t had time to update either of them. 301&#8242;s are all in place and I&#8217;m optimistic that for most use cases no-one will know the difference. More good stuff to &#8230; <a href="http://erik.labianca.org/blog/2009/09/blog-re-integration-complete/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve merged my two blogs back into one since I haven&#8217;t had time to update either of them. 301&#8242;s are all in place and I&#8217;m optimistic that for most use cases no-one will know the difference. More good stuff to come!</p>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/09/blog-re-integration-complete/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Get started using Mercurial source control in 5 minutes or less</title>
		<link>http://erik.labianca.org/blog/2009/05/get-started-using-mercurial-source-control-in-5-minutes-or-less/</link>
		<comments>http://erik.labianca.org/blog/2009/05/get-started-using-mercurial-source-control-in-5-minutes-or-less/#comments</comments>
		<pubDate>Tue, 12 May 2009 14:51:40 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Information]]></category>
		<category><![CDATA[Technical]]></category>
		<category><![CDATA[dvcs]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[revision control]]></category>
		<category><![CDATA[source control]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.cto-at-large.com/?p=121</guid>
		<description><![CDATA[While, in a previous post I talked about how DVCS is the modern form of source control and promised I&#8217;d show you how to do it, quickly and easily. So let&#8217;s get started! I&#8217;m going to use Mercurial because, well, &#8230; <a href="http://erik.labianca.org/blog/2009/05/get-started-using-mercurial-source-control-in-5-minutes-or-less/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>While, in a previous post I talked about how DVCS is the modern form of source control and promised I&#8217;d show you how to do it, quickly and easily. So let&#8217;s get started! I&#8217;m going to use Mercurial because, well, I am.</p>
<p>First, you need to download the Mercurial package for your system. If you use a mac with <a href="http://www.macports.org/">macports</a> you can just use type <code>sudo port install mercurial</code>. You could also use the very nice mac .dmg packages from <a href="http://mercurial.berkwood.com/">berkwood</a>. On Ubuntu, you should be able to <code>sudo apt-get install mercurial</code>. On windows, you&#8217;ll probably want to download and install <a href="http://bitbucket.org/tortoisehg/stable/wiki/Home">TortoiseHG</a>. BitBucket makes it complicated to find the download link so just click <a href="http://bitbucket.org/tortoisehg/stable/downloads/">this one</a> instead. You&#8217;ll want the file in the top of the list. Right now, that is <a href="http://bitbucket.org/tortoisehg/stable/downloads/TortoiseHg-0.7.5-hg-1.2.1.exe">TortoiseHg-0.7.5-hg-1.2.1.exe</a>.</p>
<p>So, you should now have a working mercurial command line executable. To try it out, open your shell of choice and type <code>hg</code>.You should get something like this:<br />
<code>
<pre>
loki:dtest erik$ hg
Mercurial Distributed SCM

basic commands:

 add        add the specified files on the next commit
 annotate   show changeset information per file line
 clone      make a copy of an existing repository
 commit     commit the specified files or all outstanding changes
 diff       diff repository (or selected files)
 export     dump the header and diffs for one or more changesets
 init       create a new repository in the given directory
 log        show revision history of entire repository or files
 merge      merge working directory with another revision
 parents    show the parents of the working dir or revision
 pull       pull changes from the specified source
 push       push changes to the specified destination
 remove     remove the specified files on the next commit
 serve      export the repository via HTTP
 status     show changed files in the working directory
 update     update working directory

use "hg help" for the full list of commands or "hg -v" for details
</pre>
<p></code></p>
<p>Now comes the fun part. Simply navigate to the directory you want to put under revision control and run
<pre><code>hg init</code></pre>
<p>. This will create the <code>.hg</code> directory which stores your local repository.</p>
<p>Your next step should be to create a <code>.hgignore</code> file. This file will tell mercurial which file types to ignore. It can use two syntaxes, standard shell globs and also regular expressions. This should give you enough flexibility to eliminate all those pesky auto-generated files, movies, etc from your project directory. Here&#8217;s what I&#8217;ve been using for drupal projects lately, it should give you a good idea of what sort of patterns you might use.</p>
<pre><code>
syntax: glob
*.pyc
*~
hostmeta.ini
Thumbs.db
.DS_Store
*.exe
*.flv
*.mov
*.zip
*.avi
*.wmv
*.dv
*.psd
*.LCK

syntax: regexp
.*\#.*\#$
^files.*
^web/files.*
.*CVS.*
</code></pre>
<p>Now that we&#8217;ve got an <code>.hgignore</code> file, let&#8217;s check it into revision control. Simply execute</p>
<pre><code>
hg add .hgignore
</code></pre>
<p> and then</p>
<pre><code>
hg commit -m 'added .hgignore file'
</code></pre>
<p>. The <code>add</code> tells mercurial to flag the file revision control. The <code>commit</code> command will actually push the contents of the file into the revision control repository.</p>
<p>Now, let&#8217;s put your files under revision control. At this point, since you have a <code>.hgignore</code> file that eliminates all the files you don&#8217;t want controlled, you can run the</p>
<pre><code>
hg status
</code></pre>
<p> command. It will show you all the status of all the files in the revision controlled tree. File which are checked in and already up to date or ignored will not show up on the listing. For a newly created <a href="http://www.djangoproject.org/">Django</a> project with a single app in it, you might see something like this:</p>
<pre><code>
loki:dtest erik$ hg status
? __init__.py
? manage.py
? myapp/__init__.py
? myapp/models.py
? myapp/tests.py
? myapp/views.py
? settings.py
? urls.py
loki:dtest eri
</code></pre>
<p>Now, if all the with ? in front of them are ones you want to add to revision control, simply execute
<pre><code>
hg addremove
</code></pre>
<p>. This will recurse the tree and add all the missing files, and mark any files that have disappeared from your local tree as deleted in the repository. Then, you just run</p>
<pre><code>
hg commit -m 'added first set of files'
</code></pre>
<p> in order check everything in.</p>
<p>If you had files with ? that you don&#8217;t want under revision control, you will need to add expressions to your <code>.hgignore</code> file to ignore them and re-run status. You can also just use add manually on your files, but in my opinion the addremove feature is such a nice addition and hg status is such a powerful feature you will be much better off taking the time to maintain an ignore file.</p>
<p>So, you&#8217;ve now got a copy of your code in revision control. A simple <code>hg status</code> should return blank, indicating that your working copy is in sync with the repository. So let&#8217;s check out that safety net.</p>
<p>Let&#8217;s make a random change to our urls.py.</p>
<pre><code>
echo "# this comment is really lame" >> urls.py
</code><code></code></pre>
<p>And now run <code>hg status</code> one more time. You should see something like this:</p>
<pre><code>
loki:dtest erik$ hg status
M urls.py
</code></pre>
<p>The <code>M</code> prefix indicates that the file has been modified. Now, let&#8217;s see what exactly was modified. Run <code>hg diff</code>. You should get a result like this:</p>
<pre><code>
loki:dtest erik$ hg diff
diff -r 7844b323276e urls.py
--- a/urls.py   Tue May 12 02:56:05 2009 -0400
+++ b/urls.py   Tue May 12 02:58:47 2009 -0400
@@ -15,3 +15,4 @@
     # Uncomment the next line to enable the admin:
     # (r'^admin/', include(admin.site.urls)),
 )
+# this comment is really lame
</code></pre>
<p>As you can see, we have a nicely unified diff indicating that we added a single line. If you installed a GUI package, you can probably use the GUI to bring up a much more nicely formatted GUI change viewer.</p>
<p>So, now we know what we changed. That&#8217;s pretty useful, but how do we get rid of that change? Again, really easy, simply use the
<pre><code>hg revert</code></pre>
<p> command. If you don&#8217;t want to revert all your changes, you can run
<pre><code>hg revert urls.py</code></pre>
<p> for instance, which will only revert changes to <code>urls.py</code>.</p>
<p>If you revert a file and then run hg status, you&#8217;ll note that the file is no longer marked as modified and there is a new <code>? urls.py.orig</code> file which mercurial has nicely decided to keep in case you change your mind. I guess .orig would be a good suffix to add to your <code>.hgnore</code> file!</p>
<p>Obviously we&#8217;ve just barely begun to scratch the surface of mercurial and DVCS&#8217;s in general, but there&#8217;s plenty of time for more learning. Even if you just use it for diffs and revert, you&#8217;re getting great value from your DVCS and are ready to add in more functionality as you need it. Good luck!</p>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/05/get-started-using-mercurial-source-control-in-5-minutes-or-less/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>DVCS: Modern Source Control aka the Programmers Safety Net</title>
		<link>http://erik.labianca.org/blog/2009/05/dvcs-modern-source-control-aka-the-programmers-safety-net/</link>
		<comments>http://erik.labianca.org/blog/2009/05/dvcs-modern-source-control-aka-the-programmers-safety-net/#comments</comments>
		<pubDate>Mon, 04 May 2009 17:28:31 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Information]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Technical]]></category>
		<category><![CDATA[Best Practices]]></category>

		<guid isPermaLink="false">http://www.cto-at-large.com/2009/05/dvcs-modern-source-control-aka-the-programmers-safety-net/</guid>
		<description><![CDATA[Revision control is a key tool for modern software engineers. It provides a safety net for the individual developer, and provides a collaborative framework that allows many developers to work on the same project without fear of stepping on each &#8230; <a href="http://erik.labianca.org/blog/2009/05/dvcs-modern-source-control-aka-the-programmers-safety-net/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Revision control is a key tool for modern software engineers. It provides a safety net for the individual developer, and provides a collaborative framework that allows many developers to work on the same project without fear of stepping on each others toes.</p>
<p><a href="http://www.flickr.com/photos/35545469@N06/3290184656/"><img height="300" border="0" width="450" style="margin: 5px;" class="" alt="" src="http://erik.labianca.org/blog/wp-content/uploads/2009/05/skydivers.jpg" title="Skydivers from The Passion Man" /></a>
<p>Revision control or isn&#8217;t a new idea. <a href="http://www.gnu.org/software/rcs/rcs.html">RCS</a> and it&#8217;s descendant, <a href="http://www.nongnu.org/cvs/">CVS</a>, date back to the early 80&#8242;s, and they in turn were based on even older systems. That said, many programmers still aren&#8217;t using it. Eric Sink blames it on <a href="http://www.ericsink.com/scm/scm_intro.html">lack of training</a>. Ben Collins-Sussman thinks it&#8217;s because <a href="http://blog.red-bean.com/sussman/?p=82">80% of programmers aren&#8217;t &quot;Alphas&quot;</a>. Andrew Smith (the number one hit on Google, I might add) thinks it&#8217;s because <a href="http://littlesvr.ca/grumble/2008/07/24/why-dont-people-use-version-control/">takes too long to learn and it&#8217;s hard to set up a server</a>. I&#8217;ll plead the fifth and say I hope I can be a part of the solution instead of the problem!</p>
<p>In any case, up until the last few years, revision control systems were centralized. That is, there was a single central repository of code to which contributors connected, checking out code and checkin in their changes. <a href="http://subversion.tigris.org/">Subversion</a> is the latest of these centralized systems. It was developed specifically to be CVS without the worst of the bugs, and to that end it is very successful. If you want great tools support, have a reasonable sized team, like non-mind-bending behavior, and you only work across a local network anyway, subversion is a great system. </p>
<p>However, many developers have become frustrated with centralized version control. Nobody wants to be accused of &#8216;breaking the build&#8217;, so naturally the frequency of checkins decreases. To the same end, to avoid newbies breaking the build, project administrators don&#8217;t give out commit access lightly. The end result is that developers lose the safety-net aspect revision control. I&#8217;ve been witness to developers making a copy of their source code, out of revision control, because they&#8217;re so afraid they might check in something bad.</p>
<p>In addition, since core contributors are the only ones with commit access to the revision control system, most contributions must come as patches. These patches can be tricky to create in the best of times, but with scale this problem becomes untenable. Just check out the linux kernel mailing list to get a sense of the problem.</p>
<p>The answer to these problems is called a <a href="http://en.wikipedia.org/wiki/Distributed_revision_control">Distributed Version Control System</a>, or DVCS. There are quite a few of these animals out there. Most recently, it seems as if the open source playing field is being dominated by three: <a href="http://bazaar-vcs.org/">Bazaar</a>, <a href="http://git-scm.com/">Git</a>, and <a href="http://www.selenic.com/mercurial/wiki/">Mercurial</a>. All of these systems have their plusses and minusses, but they are all open source and work well enough to get the job done.</p>
<p>Distributed version control systems share quite a few things in common. Instead of using a line or <a href="http://en.wikipedia.org/wiki/Tree_data_structure">tree</a> with named revision numbers to store the change history, distributed revision control systems use <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">directed acyclic graphs</a>. This basically means that you can have multiple valid lines or trees at the same time. Hence, distributed.</p>
<p>What this means to you (the developer) is that you get a local copy of the entire repository available to you at all times. That means you can check in, revert, merge, create branches, etc without a network connection.</p>
<p>It also means that you always have access to that revision control sandbox. It allows you to &#8216;check in early, check in often&#8217;, and still not live in fear of breaking the build or disrupting somebody elses work with your bad code. When your code is good and ready, you can review it&#8217;s entire change history, merge in any changes, and submit the entire changeset directly to the central repository or to a core committer as a patch.</p>
<p>Having a local copy of the repository also means that you have a more complete copy of your source code at every developer location  with a DVCS than you would with a traditional VCS.</p>
<p>I&#8217;ll get into the nitty-gritty of how to actually start using DVCS (and how&#8217;s it&#8217;s arguably faster and easer than svn) in another post, but for now, just get out there and use something. Not using source control is like skydiving without a parachute.</p>
<p>References:</p>
<ul>
<li>James Golick has a friendly <a href="http://jamesgolick.com/tags/dvcs.html">introduction</a> to DVCS logic.</li>
<li>Eric Sink has some solid posts about <a href="http://www.ericsink.com/scm/source_control.html">Source Control</a> and <a href="http://www.ericsink.com/entries/dvcs_dag_1.html">DVCS and DAGs</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/05/dvcs-modern-source-control-aka-the-programmers-safety-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Developers for Smarties: 5 Traits Of Great Programmers</title>
		<link>http://erik.labianca.org/blog/2009/02/developers-for-smarties-5-traits-of-great-programmers/</link>
		<comments>http://erik.labianca.org/blog/2009/02/developers-for-smarties-5-traits-of-great-programmers/#comments</comments>
		<pubDate>Thu, 26 Feb 2009 13:29:22 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Information]]></category>

		<guid isPermaLink="false">http://www.cto-at-large.com/?p=101</guid>
		<description><![CDATA[While the wonderful folk in the world of information technology would have us all believe that all we need to do is buy their latest &#8220;solution&#8221;, the facts of the matter are that if you&#8217;re serious about leveraging technology eventually &#8230; <a href="http://erik.labianca.org/blog/2009/02/developers-for-smarties-5-traits-of-great-programmers/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>While the wonderful folk in the world of information technology would have us all believe that all we need to do is buy their latest &#8220;solution&#8221;, the facts of the matter are that if you&#8217;re serious about leveraging technology eventually you are going to need go beyond what came free in the box.</p>
<div class="zemanta-img zemanta-action-dragged" style="margin: 1em; display: block;">
<div class="wp-caption alignright" style="width: 190px"><a href="http://www.flickr.com/photos/49503056657@N01/561370770"><img title="Hacker Barbie" src="http://farm2.static.flickr.com/1401/561370770_19406fb137_m.jpg" alt="Hacker Barbie" width="180" height="240" /></a><p class="wp-caption-text">Image by nic221 via Flickr</p></div>
</div>
<p>Going beyond what came free in the box typically means hiring somebody calling themselves a Programmer, Developer, Software Engineer or even Software Architect. If they worked someplace interesting or for themselves, they might prefer terms like Hacker, Geek or Programming Rock Star. Unfortunately, none of this stuff really means anything! Having worked with and around these guys for a few years I can say with great confidence that their ability to program is in no way related to these accolades. Unfortunately, involvement with large companies or ostensibly successful high-profile projects doesn&#8217;t necessarily mean anything either. It&#8217;s not that hard to hitch your wagon to a train.</p>
<p>So what are you looking for?</p>
<ol>
<li><strong>Engaged with Technology</strong>. I&#8217;ve never met a good programmer who didn&#8217;t get excited about almost any technical project. It could be simple like &#8220;hey did you see the new Google fizzbuzz application&#8221; or complicated like &#8220;hey, did you hear they added support for asyncronous transaction replication to the latest version of MySQL&#8221;? Either way, a good programmer will engage. Bear in mind, the first response is likely to be &#8220;That&#8217;s BS, MySQL sucks, use MS SQL Server&#8221;, but they&#8217;ll engage. If they sit there like a dead fish and don&#8217;t even ask you what you are talking about, be afraid. Caveat: You need to be able to be sufficiently technical to engage in a discussion with a programmer. If you can&#8217;t, chances are you aren&#8217;t equipped to manage one either, so why try to hire one?</li>
<li><strong>Problem Solving</strong>. To a degree beyond most professions, programming is about problem solving. See my previous post on Levels of Work, but frankly, you can&#8217;t afford to have many Stratum I programmers on your staff unless you&#8217;re running an internship program. You want the guys that can engage problems head on, and come out with solutions. Good programmers love to hear about what your problems in an interview, and would love to offer ideas as to how to solve them. Give them the chance.</li>
<li><strong>Language Agnostic</strong>. Great programmers are familiar with more than one language. Actually, more like more than ten. It should be obvious, then, that looking for somebody with 10 years of C++ experience is a sure-fire way to eliminate great candidates. Bear in mind, if your goal is to create the next revision of the C++ standard, you really do need somebody who is deeply involved in the C++ community and has been for 10 years. Most of us, however, are much better off using the right tool for the job, and frankly, sometimes that means using a new programming language. Anybody who hasn&#8217;t even dabbled in another environment for 10 years probably won&#8217;t adapt well to the future. Computer languages aren&#8217;t that complicated, and even better, learning another language adds a ton of great perspective to every program you write. The obvious extension to this rule is that they should also be familiar with more than one development framework. Every Rails programer should have at least checked out what Django has to offer by perusing their website. J2EE programmers should at least know that they aren&#8217;t just WebLogic or WebSphere programmers, but that they are also Glassfish or JBoss programmers.</li>
<li><strong>Understands Development Process</strong>. If you haven&#8217;t seen <a class="zem_slink" title="The Joel Test" rel="wikipedia" href="http://en.wikipedia.org/wiki/The_Joel_Test">The Joel Test</a> by now, you&#8217;re missing out. Ditto for any programmer that isn&#8217;t familiar with Specifications, <a class="zem_slink" title="Revision control" rel="wikipedia" href="http://en.wikipedia.org/wiki/Revision_control">Revision Control</a>, Defect Tracking and Automated Build Systems. Good programmers whine about how they never get complete enough specs, or say they gave up on specs in favor of agile methods. Good programmers will happily bore you to tears with the reasons you should use distributed version control instead of that lame old CVS clone you&#8217;re using. If they say something dumb like &#8220;I don&#8217;t use revision control, I make backups to floppy discs&#8221;, run away. Quickly.</li>
<li>
<div class="zemanta-img" style="margin: 1em; display: block;">
<div>
<dl class="wp-caption alignright" style="width: 212px;">
<dt class="wp-caption-dt"><a href="http://commons.wikipedia.org/wiki/Image:Programming_language_textbooks.jpg"><img title="A selection of programming language textbooks ..." src="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Programming_language_textbooks.jpg/202px-Programming_language_textbooks.jpg" alt="A selection of programming language textbooks ..." width="202" height="138" /></a></dt>
<dd class="wp-caption-dd zemanta-img-attribution" style="font-size: 0.8em;">Image via <a href="http://commons.wikipedia.org/wiki/Image:Programming_language_textbooks.jpg">Wikipedia</a></dd>
</dl>
</div>
</div>
<p><strong>Continuous Learning</strong>. Would you want a brain surgeon who last updated his technique in 1985? Maybe you would, but you definitely don&#8217;t want a programmer with skills that old. Technology is the fastest moving set of skills in the workplace today, and among technology, software is arguably the fastest moving of all. Programmers are the mechanics of software, and they need to be up to date. Good programmers are always looking for an excuse to try something new. Suggest a possible Rails app to a guy who&#8217;s been doing J2EE and, all things being equal, the correct response is &#8220;I&#8217;m familiar with it, but never had the chance to use it for a Project&#8221;. Now, bear in mind she may be afraid to sidetrack her career by becoming the Junior Rails Programmer (TM), but you wouldn&#8217;t be so silly as to try to pull that stunt anyway, right?</li>
</ol>
<p>In short, hiring a programmer is hiring somebody to think. They have to be able to think out of the box of convention while still staying in the box of what can actually be done using the technology available. They have to continually update their skills, and enjoy doing it. I&#8217;ve barely scratched the surface of what makes a great programmer, but here&#8217;s some other opinions to consider as well:</p>
<ul>
<li><a title="http://www.codinghorror.com/blog/archives/001225.html" href="http://www.codinghorror.com/blog/archives/001225.html" target="_blank">The Ferengi Programmer</a> and it&#8217;s<a title="http://www.codinghorror.com/blog/archives/000856.html" href="http://www.codinghorror.com/blog/archives/000856.html" target="_blank"> followup</a></li>
<li><a title="http://www.codinghorror.com/blog/archives/000895.html" href="http://www.codinghorror.com/blog/archives/000895.html" target="_blank">Learning, or Learning How to Learn</a></li>
<li><a title="http://www.joelonsoftware.com/articles/HighNotes.html" href="http://www.joelonsoftware.com/articles/HighNotes.html" target="_blank">Hitting the High Notes</a></li>
</ul>
<div class="zemanta-pixie" style="margin-top: 10px; height: 15px;"><a class="zemanta-pixie-a" title="Zemified by Zemanta" href="http://reblog.zemanta.com/zemified/1cf7becd-6083-48d3-8a94-c70d3f500c8c/"><img class="zemanta-pixie-img" style="border: medium none; float: right;" src="http://img.zemanta.com/reblog_e.png?x-id=1cf7becd-6083-48d3-8a94-c70d3f500c8c" alt="Reblog this post [with Zemanta]" /></a></div>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/02/developers-for-smarties-5-traits-of-great-programmers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Virtualization Technology Overview</title>
		<link>http://erik.labianca.org/blog/2009/02/virtualization-technology-overview/</link>
		<comments>http://erik.labianca.org/blog/2009/02/virtualization-technology-overview/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 14:00:05 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Information]]></category>
		<category><![CDATA[virtualization]]></category>

		<guid isPermaLink="false">http://www.cto-at-large.com/?p=92</guid>
		<description><![CDATA[One of the hottest buzzwords in technology today is virtualization. Unforrtunately, virtualization by itself covers a vast array of potential technologies. Let&#8217;s look at the word itself first. Virtualization implies taking something &#8220;real&#8221; and &#8220;virtualizing&#8221; it, or making it &#8220;virtual&#8221;. &#8230; <a href="http://erik.labianca.org/blog/2009/02/virtualization-technology-overview/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>One of the hottest buzzwords in technology today is virtualization. Unforrtunately, virtualization by itself covers a vast array of potential technologies.</p>
<p>Let&#8217;s look at the word itself first. Virtualization implies taking something &#8220;real&#8221; and &#8220;virtualizing&#8221; it, or making it &#8220;virtual&#8221;. Typically, this is exactly what is going on with virtualization technologies, the differences lie in what exactly is being virtualized.</p>
<p><strong>Storage Virtualization</strong></p>
<p>At the very bottom of the technology stack lies storage virtualization. Unfortunately, the storage industry is probably the most arcane of all IT sectors, and the inability to agree on what truly comprises storage virtualization technology is a great case in point.</p>
<div class="zemanta-img" style="margin: 1em; display: block;">
<div>
<dl class="wp-caption alignright" style="width: 212px;">
<dt class="wp-caption-dt"><a href="http://commons.wikipedia.org/wiki/Image:Rack001.jpg"><img title="A typical server &quot;rack&quot;, commonly se..." src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Rack001.jpg/202px-Rack001.jpg" alt="A typical server &quot;rack&quot;, commonly se..." width="202" height="269" /></a></dt>
<dd class="wp-caption-dd zemanta-img-attribution" style="font-size: 0.8em;">Image via <a href="http://commons.wikipedia.org/wiki/Image:Rack001.jpg">Wikipedia</a></dd>
</dl>
</div>
</div>
<p>From a layman&#8217;s perspective storage virtualization should simply mean that your OS images don&#8217;t have to worry about where their storage comes from, it&#8217;s just there. Virtualization should allow it to be resized, move to new physical hardware, and isolated from hardware failure, all without effecting the running operating system and storage. In practice, vendors will call almost anything storage virtualization, so make sure you put on your skeptics hat when you hear them claiming to support it.</p>
<p>Coupled with server-side operating system virtualization, true storage virtualization delivers a one-two knockout punch to old fashioned IT. Expect to see this technology stabilize quickly as the industry gets excited about cloud compuing.</p>
<p><strong>Operating System Hardware Virtualization</strong></p>
<p>Lately there&#8217;s been lots of news over OS virtualization. <a class="zem_slink" title="VMware" rel="homepage" href="http://www.vmware.com/">VMWare</a>, Xen, Parralels, <a class="zem_slink" title="Sun xVM" rel="homepage" href="http://sun.com/xvm">Sun xVM</a>, and <a class="zem_slink" title="Hyper-V" rel="wikipedia" href="http://en.wikipedia.org/wiki/Hyper-V">Microsoft Hyper-V</a> are all this sort of technology. Newer Intel and AMD processors even have native instructions to make this sort of virtualization more efficient. In short, OS virtualization allows you to run several complete virtual systems on a single virtual machine host.</p>
<p>Operating system virtualization is revolutionary when it comes to maintaining datacenters. Most server applications are not cpu, memory, or even I/O bound. Rather, they are IT staff bound, meaning that every application gets to run on it&#8217;s own server because IT doesn&#8217;t dare install it any other way.</p>
<p>OS Virtualization seperates the OS image from the hardware support, allowing you to provision a host operating system as specified by a specific application, while migrating it from machine to machine as needs dictate.</p>
<p>There is a ton of R&amp;D going into OS virtualization, both on the client and server side. Modern hypervisors allow you to migrate a running virtual machine from one physical host to another, allow for automatic failover and load balancing, and integrate with backup software. At this point, if you are provisioning new server systems without using virtualization, you ought to be asking yourself why.</p>
<p>On the client side, OS virtualization is pretty cool for tech people, but in my book still isn&#8217;t where it needs to be. There is no reason for most computer users to run their OS on native hardware, yet that hasn&#8217;t happened. Until it does, you&#8217;ll be stuck dealing with rebuilding your system every year or so to clear out the cruft or to handle a system migration. Technologies like VMWare ACE are trying to tackle this proble, but the technology has a long way to go before it catches up with server virtulization with respect hardware isolation.</p>
<p><strong>Operating System Partitioning</strong></p>
<p>Another very interesting technology in the operating sytem world is system partitioning. OpenSolaris Zones, FreeBSD Jails, <a class="zem_slink" title="NYSE: IBM" rel="stockexchange" href="http://finance.yahoo.com/q?s=IBM">IBM</a> LPARS and Linux vServers are all variants of this technology. In short, the runtime environment of the operating system is partitioned off from the host system while continuing to share a kernel.</p>
<p>Since kernels tend to be pretty reliable, this allows you to have some of the principle benefits of hardware virtualization (application isolation) without many of the costs (performance and memory overhead).</p>
<p>Unfortunately, this type of technology hasn&#8217;t really made any headway in the Microsoft stack, so it&#8217;s not used very heavily. Nonetheless, it&#8217;s something to keep your eyes on as the world moves towards cloud computing etc.</p>
<p><strong>Runtime Virtualization</strong></p>
<p>Moving farther up the application stack is runtime virtualization. <a class="zem_slink" title=".NET Framework" rel="homepage" href="http://www.microsoft.com/net/">Microsoft .NET</a> and Java are the 800lb gorilla&#8217;s in thie space. Runtime virtualization brings much of the application isolation benefits of OS-level virtualization schemes without incurring the much of the complexity of maintaining multiple operating system images.</p>
<p>The downside is obviously that software has to be explicitly targetted at a virtualization friendly runtime. However, you should understand the development and deployment benefits of targetting such an environment before choosing a development platform for a new project. They are by no means insignificant, and a lot of very smart people are working very hard at moving this technology forward.</p>
<p>Projects using Runtime Virtualization that I find particularly interesting are JRuby and Jython for Java and IronRuby/IronPython for .NET. These projects bring the development benefits of modern scripting languages to the deployment benefits of runtime virtualization. Look for a lot more good stuff from these guys.</p>
<p><strong><br />
</strong></p>
<div class="zemanta-pixie" style="margin-top: 10px; height: 15px;"><a class="zemanta-pixie-a" title="Zemified by Zemanta" href="http://reblog.zemanta.com/zemified/8505ec57-e353-4f6f-aefa-5b64f97fa8e1/"><img class="zemanta-pixie-img" style="border: medium none; float: right;" src="http://img.zemanta.com/reblog_e.png?x-id=8505ec57-e353-4f6f-aefa-5b64f97fa8e1" alt="Reblog this post [with Zemanta]" /></a></div>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/02/virtualization-technology-overview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vendor negotiation tips</title>
		<link>http://erik.labianca.org/blog/2009/02/vendor-negotiation-tips/</link>
		<comments>http://erik.labianca.org/blog/2009/02/vendor-negotiation-tips/#comments</comments>
		<pubDate>Mon, 23 Feb 2009 19:02:33 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Purchasing]]></category>
		<category><![CDATA[Business]]></category>
		<category><![CDATA[Negotiation]]></category>
		<category><![CDATA[Pricing]]></category>
		<category><![CDATA[Vendor]]></category>

		<guid isPermaLink="false">http://www.cto-at-large.com/?p=85</guid>
		<description><![CDATA[Stephen Foskett and Martin Glassborow have some great posts about pricing and negotiation lately, and I thought I&#8217;d jump into the fray. In my experience, there are a few other things to consider, especially if you&#8217;re new at this. Much &#8230; <a href="http://erik.labianca.org/blog/2009/02/vendor-negotiation-tips/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a title="http://gestaltit.com/index.php/top/stephen/lets-talk-pricing/" href="http://gestaltit.com/index.php/top/stephen/lets-talk-pricing/" target="_blank">Stephen Foskett</a> and<a title="http://storagebod.typepad.com/storagebods_blog/2009/02/deal-or-no-deal.html" href="http://storagebod.typepad.com/storagebods_blog/2009/02/deal-or-no-deal.html" target="_blank"> Martin Glassborow</a> have some great posts about pricing and negotiation lately, and I thought I&#8217;d jump into the fray. In my experience, there are a few other things to consider, especially if you&#8217;re new at this. Much of this is standard negotiation technique, but tech folks don&#8217;t necessarily come with the same level of negotiation experience as some other disciplines so I think it bears repeating.</p>
<div class="zemanta-img" style="margin: 1em; display: block;">
<div>
<dl class="wp-caption alignright" style="width: 250px;">
<dt class="wp-caption-dt"><a href="http://www.flickr.com/photos/12028171@N00/266380311"><img title="NetApp FAS270" src="http://farm1.static.flickr.com/107/266380311_595c39aa30_m.jpg" alt="NetApp FAS270" width="240" height="160" /></a></dt>
<dd class="wp-caption-dd zemanta-img-attribution" style="font-size: 0.8em;">Image by <a href="http://www.flickr.com/photos/12028171@N00/266380311">mondopiccolo</a> via Flickr</dd>
</dl>
</div>
</div>
<ol>
<li><strong>Everything is negotiable</strong>. The corollary of this is &#8220;you will not get what you do not ask for&#8221;. Bear in mind you may not get it even by asking, but you won&#8217;t know if you don&#8217;t ask.</li>
<li><strong>Keep your options open</strong>. Make sure you keep as broad a scope on the negotiation as possible. It is in the vendor&#8217;s best interest to lock you into thinking you need some aspect of his solution, which he can then use to lever you into considering competitive products that are out of your league. Instead, when you&#8217;re negotiating for a new internet pipe, negotiate from the stance that you could downgrade to a cable-modem and co-locate your services<strong>.</strong></li>
<li><strong>Focus on your business needs</strong>. Often-times you may think you need one thing, but you actually need another. While you need to know the specifics of what you&#8217;re buying, if you continually bring the negotiation back to the business problems you are trying to solve, you may find your vendors are able to offer you a better product from a different part of the house. This is another form of keeping your options open, but it&#8217;s very important, because it keeps the onus on the vendor to meet your needs rather than just quote you a bill of goods.</li>
<li><strong>Put time on your side.</strong> Simply put, start negotiations early and make sure your deadlines aren&#8217;t hard ones. Like Martin says, align your purchasing cycles with your vendors quarterly sales targets. The more time you can afford to take, the more time you have for the vendor to get desperate to close the deal and scare up some better pricing. Don&#8217;t overdo it though, your long term relationship will suffer if you are always taking vendors for a ride and never buying.</li>
<li><strong>Understand what you are buying</strong>. Unfortunately, at least at the scale I am usually buying, I know more about the technical details of the product class and even the specific products being discussed than the vendor reps. I&#8217;ve found if I don&#8217;t know more, I&#8217;m likely to get taken for a ride with things I don&#8217;t need. This plays heavily into the next point as well. You simply can&#8217;t afford to buy stuff that won&#8217;t meet your needs fully, and nobody but you can really ensure that.</li>
<li><strong>Demand a demo</strong>. When you&#8217;re spending big bucks, this usually isn&#8217;t too hard. But you can still get demo&#8217;s if you&#8217;re buying less, and frankly, especially with the economy as it is lately, if the vendor won&#8217;t take you seriously enough to get you in front of the kit they want to sell you, you don&#8217;t want to do business. There&#8217;s really no reason to purchase something you aren&#8217;t 110% confident is going to meet your needs, so prove it to yourself before signing anything.</li>
</ol>
<p>In conclusion, if there&#8217;s a single rule I&#8217;ve found, it&#8217;s that there is no shortcut. A perfect <a class="zem_slink" title="Request for Proposal" rel="wikipedia" href="http://en.wikipedia.org/wiki/Request_for_Proposal">RFP</a> is still just the first step towards getting a good solution for a great price. You&#8217;ll still have to learn all there is to know about the product, build a relationship with a vendor, and make sure you&#8217;re buying the right thing. Don&#8217;t be seduced by the siren&#8217;s call of a &#8220;write the check solution&#8221;, the only problem it will solve is your vendor&#8217;s cash-flow.</p>
<div class="zemanta-pixie" style="margin-top: 10px; height: 15px;"><a class="zemanta-pixie-a" title="Zemified by Zemanta" href="http://reblog.zemanta.com/zemified/bd14886d-b8d5-4fe3-bd31-92c6d243b8c4/"><img class="zemanta-pixie-img" style="border: medium none; float: right;" src="http://img.zemanta.com/reblog_e.png?x-id=bd14886d-b8d5-4fe3-bd31-92c6d243b8c4" alt="Reblog this post [with Zemanta]" /></a></div>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/02/vendor-negotiation-tips/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Level of Work: Choose the right person for the task</title>
		<link>http://erik.labianca.org/blog/2009/02/level-of-work-choose-the-right-person-for-the-job/</link>
		<comments>http://erik.labianca.org/blog/2009/02/level-of-work-choose-the-right-person-for-the-job/#comments</comments>
		<pubDate>Mon, 23 Feb 2009 16:36:14 +0000</pubDate>
		<dc:creator>erik</dc:creator>
				<category><![CDATA[Management]]></category>
		<category><![CDATA[Project management]]></category>

		<guid isPermaLink="false">http://www.cto-at-large.com/?p=74</guid>
		<description><![CDATA[In the managerial world, at least in some circles, Elliott Jacques is well known for his theory of requisite organization. While his work runs against some of the conventional wisdom of organizational theory, his Level of Work concept has merit &#8230; <a href="http://erik.labianca.org/blog/2009/02/level-of-work-choose-the-right-person-for-the-job/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In the managerial world, at least in some circles, <a class="zem_slink" title="Elliott Jaques" rel="wikipedia" href="http://en.wikipedia.org/wiki/Elliott_Jaques">Elliott Jacques</a> is well known for his theory of <a class="zem_slink" title="Requisite organization" rel="wikipedia" href="http://en.wikipedia.org/wiki/Requisite_organization">requisite organization</a>. While his work runs against some of the conventional wisdom of <a class="zem_slink" title="Organizational studies" rel="wikipedia" href="http://en.wikipedia.org/wiki/Organizational_studies">organizational theory</a>, his Level of Work concept has merit for anyone. Bear in mind that this is a very cursory overview of a complex theory, so in order to really put it to use you&#8217;ll need to do some more background research.</p>
<p>In short, Jacques found that human&#8217;s ability to handle task complexity increases in step-wise manner, each level of which he called a Level of Work. Each level of work can be defined in terms of its maximum Time Span of Discretion (or time span), and also by the problem solving methodology required to be able to operate effectively at that level. In addition, since the levels of work are discrete, the crux of requisite organization theory is that each level must be &#8220;stacked&#8221; appropriately within the organization for the organization to function effectively. Jacques uses the term &#8220;Cognitive Capability&#8221; to describe the level of work a given person is capable of.</p>
<div id="attachment_78" class="wp-caption alignright" style="width: 310px"><img class="size-full wp-image-78" title="38637594_141a1c401a" src="http://erik.labianca.org/blog/wp-content/uploads/2009/02/38637594_141a1c401a.jpg" alt="Hard at Work!" width="300" height="225" /><p class="wp-caption-text">Hard at Work!</p></div>
<p>Regardless, organizational theory aside, the concept of work levels brings much to bear to technical work as well. In a technical environment, Jacques theory provides a way to determine the best person for a given technical task. In addition, understanding a person&#8217;s cognitive capability makes it possible to ensure that you assign them tasks in chunks they are capable of handling.</p>
<p><strong>Stratum I &#8211; Engineers<br />
</strong></p>
<p>In a traditional environment, Stratum I is tasked with &#8220;getting the work done&#8221;. Their time-span is limited to less than 3 months, and they solve problems by trial and error. To put this into perspective, I don&#8217;t think I&#8217;ve ever seen a programming team that didn&#8217;t have at least one fabled Stratum I member. In technical terms, a person capable of Stratum I level of work could handle filling in some function definitions that were already defined, or installing a bunch of operating systems based on a procedure they were given.</p>
<p>The things a Stratum I worker can&#8217;t do is where they become fabled. This is the guy that was tasked with putting together a new OS image but forgot to check whether or not automatic updates were enabled. Or the gal tasked with creating a program to extract information from some production logs, but who didn&#8217;t bother to check if the parsing libraries they used was compatible with the production environment.</p>
<p>Bear in mind that this doesn&#8217;t make them incompetent. They may know more than most people about  OS images or log parsing, but their limited time span makes it hard for them to see a bigger picture. They are focused on the immediate task, and nothing else.</p>
<p><strong>Stratum II</strong> &#8211; <strong>Senior Engineers</strong></p>
<p>In a traditional environment, Stratum II workers are called Supervisors and charged with &#8220;making sure the work gets done&#8221;. Their time span upper bound is 1 year, and they are capable of problem solving by information gathering. In technical terms, these folk are probably considered &#8220;Senior Engineers&#8221;. They are capable of working at a higher level, such as &#8220;design and implement a system to integrate product A and B&#8221;. However, it&#8217;s important to note their limitations.</p>
<p>A time span of 1 year is still not very long. It is long enough to implement a significant chunk of code, but probably not long enough to design a chunk of code that will underpin an entire system for many years. In addition, while they are capable of problem solving by gathering information from multiple sources, they are still not really capable of serial processing. This means they will still have trouble seeing the results of their actions on a larger scope.</p>
<p>Bringing us back to the previous example, assigning the OS image creation task to a Stratum II worker would probably result in properly functioning automatic updates, but would likely fail to anticipate the need to roll out the next service pack or hardware generation. Note that this may well be ok, we don&#8217;t always have a crystal ball for the future!</p>
<p><strong>Stratum III &#8211; Architects</strong></p>
<p>In a traditional environment, Stratum III workers are called Managers and charged with &#8220;creating systems&#8221;. They have a maximum time span of 2 years and can problem solve using serial processing. In technical terms, these folk are probably your system architects, principal engineers, and perhaps VP of engineering types.</p>
<p>A 2 year time-span combined with serial processing capability is a powerful combination. These are the guys that join your team and start creating systems to speed things up. If you don&#8217;t have revision control, defect tracking, or change management, they won&#8217;t rest until they&#8217;re in place because they can see the long term benefits of these systems. They are also likely to ask lots of big-picture questions and wonder where your specifications and test procedures are.</p>
<p>Unfortunately, the ability to see the big picture isn&#8217;t always a benefit. Task a Stratum III worker with a simple task like &#8220;refactor this class&#8221; and there is a good chance it will take him 3 times as long as necessary to finish as he creates the perfect system to solve your trivial problem and whole host of other associated problems. On the other hand, these kind of system builders are the reason we have automated <a class="zem_slink" title="Code refactoring" rel="wikipedia" href="http://en.wikipedia.org/wiki/Code_refactoring">refactoring</a> tools!</p>
<p><strong>Stratum IV &#8211; Integrators</strong></p>
<p>Traditionally, Stratum IV workers are called integrators. They are often general managers, or C-Level execs with cross functional responsibilities such as operations, financial, and technical officers. They have a maximum time span of 5 years and can handle problem solving using parallel reasoning. In technical terms, you&#8217;d better hope your <a class="zem_slink" title="Chief technical officer" rel="wikipedia" href="http://en.wikipedia.org/wiki/Chief_technical_officer">CTO</a> can operate at this level. Many very senior engineers operate at this level and above as well. The defining trait of Stratum IV ability is following multiple lines of serial reasoning concurrently.</p>
<p>For instance, the choice of a development platform in a reasonably large company requires at least Stratum IV work level capability. There will be potentially dozens of ramifications of such a choice, from your ability to hire in talent, to the efficiency of development, to the ease of deployment, to the production environment security and finally to the usability of the final product. Each of these lines of reasoning will unfold for years, and the ability to &#8220;zoom out&#8221; in perspective enough to focus on what is important while ignoring the mass of irrelevant details is of paramount importance.</p>
<p>There are lots of other technical tasks that fall under Stratum IV and higher time span. Language design, API decisions and Enterprise Systems Architecture come to mind immediately. What others can you think of?</p>
<p><strong>Conclusion</strong></p>
<p>In conclusion, it&#8217;s important to recognize the work level capability of the folks on your team, and the complexity of the tasks you assign. It&#8217;s possible to break down a given task to any level necessary, and if the level of detail provided matches the capability of the worker you will get much better results. As I said above, I highly recommend learning more about Jacques Capability Model to anyone involved in project management or working with teams.</p>
<p>Unfortunately, I&#8217;ve only been able to scratch the surface with this post. I&#8217;ve included a few links to other blogs that feature Jacques capability model, in addition to some amazon links to Jacques original books (which are not for the faint-hearted).</p>
<p><strong>Other Resources</strong></p>
<ul>
<li>Michelle Malay-Carter&#8217;s mission minded management blog has some great material about requisitive organization and work levels. Check out her <a title="http://www.missionmindedmanagement.com/why-cant-we-figure-out-how-to-select-leaders" href="http://www.missionmindedmanagement.com/why-cant-we-figure-out-how-to-select-leaders" target="_blank">latest post</a> about work levels, and <a title="http://www.missionmindedmanagement.com/economic-woes-will-spur-more-underemployment-which-will-spur-more-workplace-woes" href="http://www.missionmindedmanagement.com/economic-woes-will-spur-more-underemployment-which-will-spur-more-workplace-woes" target="_blank">this post</a> talking about the dangers of over-hiring I mentioned under Stratum III.</li>
<li>Tom Foster&#8217;s management skills blog is another great resource for information about work levels and job strata. He&#8217;s also a management consultant and teacher. I&#8217;ve taken his online course and recommend it highly. Check out <a title="http://www.managementblog.org/archives/2008/05/14/accurate-and-complete/" href="http://www.managementblog.org/archives/2008/05/14/accurate-and-complete/" target="_blank">this post</a> (or <a title="http://www.managementblog.org/archives/2009/02/23/judgment-and-decision-making/" href="http://www.managementblog.org/archives/2009/02/23/judgment-and-decision-making/" target="_blank">this more recent one)</a> for one entry to his large catalog of material. Tom takes an interesting story-telling approach, but stick with it.  Following the stories will pay off.</li>
<li>Jacques himself on<a href="http://www.amazon.com/gp/product/0631193138?ie=UTF8&amp;tag=erlactatla-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0631193138"> Executive Leadership: A Practical Guide to Managing Complexity (Developmental Management)</a><img style="border:none !important; margin:0px !important;" src="http://www.assoc-amazon.com/e/ir?t=erlactatla-20&amp;l=as2&amp;o=1&amp;a=0631193138" border="0" alt="" width="1" height="1" /></li>
</ul>
<div class="zemanta-pixie" style="margin-top: 10px; height: 15px;"><a class="zemanta-pixie-a" title="Zemified by Zemanta" href="http://reblog.zemanta.com/zemified/838f1183-d5af-4e28-bce3-56e199a93d51/"><img class="zemanta-pixie-img" style="border: medium none; float: right;" src="http://img.zemanta.com/reblog_e.png?x-id=838f1183-d5af-4e28-bce3-56e199a93d51" alt="Reblog this post [with Zemanta]" /></a></div>
]]></content:encoded>
			<wfw:commentRss>http://erik.labianca.org/blog/2009/02/level-of-work-choose-the-right-person-for-the-job/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

