python design patterns video lecturesIn my previous post about learning Python programming through video lectures I stopped at three lectures on Design Patterns. This time I continue from there.

If you don't know what a Design Pattern is, think of it as a simple solution to a specific problem that occurs very frequently in software design.

For example, suppose you use a bunch of unrelated pieces of code. It is a nice idea to bring the unrelated pieces of code together in a unified interface. This design pattern is called Facade. There are a bunch of patterns like this one!

The three lectures are given by Alex Martelli who works as "Über Tech Lead" for Google.

Python Design Patterns, Part I

Alex briefly covers the history and main principles of Design Patterns and quickly moves to discussing Structural and Behavioral DPs in Python.

Interesting ideas from the lecture:

  • [03:24] The name "Design Patterns" was first used by Christopher Alexander, an architect, who abstracted the idea of building buildings as building them using well known patterns which can be applied to the same problem over and over again without ever doing it the same way twice.
  • [05:30] Design Patterns are mostly applied to Object Oriented programming because it's the most widely spread programming paradigm nowadays.
  • [08:36] Design Patterns are not invented, they are discovered.
  • [10:00] Alex says that the original book Design Patterns by the Gang of Four should be read only when you are a master of DPs.
  • [13:10] Three classical categories of DPs are - Creational (deal with object instantiaton), Structural (deal with composition of objects) and Behavioral (deal with interaction of objects).
  • [14:05] "Program to an interface, not to an implementation."
  • [17:00] Use inheritance only when absolutely necessary, otherwise use "hold or wrap" principle.
  • [18:30] Never have more than one dot - Law of Demeter.
  • [18:50] Inheritance cannot restrict, use wrapping to restrict.
  • [21:41] In most of the cases when you need a single instance of something in Python, use a module instead of a class.
  • [22:23] Otherwise, just make 1 instance (without enforcing one).
  • [22:59] Singleton is also called "Highlander".
  • [24:50] There is basically no way to support subclassing well in Singleton.
  • [25:45] Monostate is also called "Borg".
  • [27:00] Python's data overriding helps in Monostate Design Pattern.
  • [29:00] Each Python's type/class is essentially a factory.
  • [32:06] Python does a "two-phase object construction".
  • [35:30] Adapter Design Pattern (it tweaks the interface to your needs).
  • [41:22] Facade Design Pattern (it provides a simple subset of a complex functionality).
  • [47:25] Bridge Design Pattern (it abstracts interface from the implementation).
  • [49:30] Decorator Design Pattern (it transparently modifies some functionality.).
  • [50:24] Proxy Design Pattern (sounds the same as decorator just for access control).
  • [51:21] Q and A!

Python Design Patterns, Part II

In this lecture Alex discusses behavioral patterns. Unlike the first part, he goes in depth of some of the patterns and explains how they can be implemented in Python.

Interesting ideas from the lecture:

  • [02:25] Template Method is a great pattern with a lousy name, a better name is "self-delegation".
  • [03:43] Example of Template Method Design Pattern (text pagination).
  • [08:50] Template Method Rationale.
  • [09:45] The "Hollywood Principle" - "don't call us, we'll call you"
  • [12:05] In Python you can also override data.
  • [13:10] Example of Template Method in Queue.Queue.
  • [14:05] If you are a good Python programmer, use Queue in threaded applications.
  • [17:45] Customizing Queue.
  • [19:30] Example of Template Method in cmd.Cmd.cmdloop.
  • [21:22] Example of Template Method in asyncore.dispatcher.
  • [22:30] Variant of Template Method - Mixin (not presented in Gang of Four book). It's a class to be multiply-inherited from and supplies organizing methods only.
  • [25:50] Template Method in DictMixin class.
  • [26:45] Example of DictMixin usage.
  • [29:00] Hooks can be factored out in another class. Two examples of this from Python's stdlib are HTML's formatter vs. writer, SAX's parser vs. handler
  • [32:40] Hook method introspection example of cmd.Cmd.docmd.
  • [33:30] There are three kinds of Template Methods - plain, factored into separate classes, and introspective.
  • [34:35] Example of all three kinds of Template Methods used in unittest.TestCase.
  • [36:17] State and Strategy Design Patterns. Very similar classes in what they do. They both factor out object's behavior.
  • [40:40] Ring buffer example done via State Design Pattern.
  • [43:35] Q and A!

Python Design Patterns, A Recap

This video lecture was presented at Google Developers day. It is a short version of the previous two video lectures. It starts with an example of Facade Design Pattern, moves on to history and all the types of design patterns.

I did not write out the interesting moments from this lecture as it was a subset of previous two lectures.

If you liked these lectures, check out this geek song about another commonly used design pattern - Model-View-Controller Song :)

Even though these were Python design patterns, to understand some of them I used Perl Design Patterns website!

Were there any interesting points in the lectures that caught your attention?

This article is part of the article series "Musical Geek Friday."
<- previous article next article ->

model view controller mvc musical geek friday songThis week on Musical Geek Friday - the Model View Controller (MVC) song!

This song was written and performed by James Dempsey, an engineer at Apple. James says that he searched iTunes for a model-view-controller song but there was none, so he wrote his own song about this topic.

The song is about a particular Design Pattern in software engineering. A Design Pattern is a simple solution to a specific problem that occurs very frequently in software design. The MVC Design Pattern was first discovered and described by Smalltalk people (see the original paper). This key idea of this pattern is that it decouples data to be displayed (model) from the code displaying the data (view) and code receiving user input (controller).

Here it the Model View Controller song:

[audio:http://www.catonmat.net/download/model_view_controller_song.mp3]

Download this song: model-view-controller song.mp3 (musical geek friday #4)
Downloaded: 40652 times

Download lyrics: model-view-controller lyrics (musical geek friday #4)
Downloaded: 2950

Talking about the MVC design pattern in this song, Ralph Johnson on squeak's mailing list comments:

The problem is that the song is NOT about Smalltalk MVC. In this song, the controller is a layer between the view and the model, which usually means it is a mediator. The song also says that the controller is copying values from one field to another, which also indicates that it is a mediator. However, in true MVC, the controller is a strategy for handling events. The events come directly to it, rather than to the view. The controller changes the model, but it is not notified by the model. When the user presses a key or moves the mouse, the controller receives the event. It checks with the view to map mouse locations into model coordinates, then interacts directly with the model. If it changes the model then the model notifies all dependents (observers), which notifes the view, which redisplays.

The song desribes Ivar Jacobson's Model/Interface/Control, in which the Control is responsible for an entire use case. It is not MVC. Jacobson's model is like the MVC model, but his Interface is a combination of View and Controller and his Control is not at all like a real Controller.

Here is the lyrics of MVC song:

Model View, Model View, Model View Controller
MVC's the paradigm for factoring your code,
into functional segments so your brain does not explode.
To achieve reusability you gotta keep those boundaries clean,
Model on the one side, View on the other, the Controller's in between.

Model View - It's got three layers like Oreos do.
Model View creamy Controller

Model objects represent your applications raison d'tre.
Custom classes that contain data logic and et cetra.
You create custom classes in your app's problem domain,
then you can choose to reuse them with all the views,
but the model objects stay the same.

You can model a throttle in a manifold,
Model level two year old.
Model a bottle of fine Chardonnay.
Model all the twaddle stuff people say.
Model the coddle in a boiling eggs.
Model the waddle in Hexley's legs.

One, two, three, four.
Model View - You can model all the models that pose for GQ.
Model View Controller

View objects tend to be controls that view and edit,
Cocoa's got a lot of those, well written to its credit.
Take an NSTextView, hand it any old Unicode string,
the user interacts with it, it can hold most anything.
But the view don't knows about the Model:
That string could be a phone number or the words of Aristotle.
Keep the coupling loose and so achieve a massive level of reuse.

Model View - All rendered very nicely in Aqua blue
Model View Controller

You're probably wondering now.
You're probably wondering how,
the data flows between Model and View.
The Controller has to mediate,
between each layer's changing state,
to synchronize the data of the two.
It pulls and pushes every changed value.
Yeah.

Model View - mad props to the smalltalk crew!
for Model View Controller

Model View - it's pronouced Oh Oh not Uh Uh
Model View Controller

There's a bit more on this story,
a few more miles upon this road,
well nobody seems to get much glory
writing controller code.
Well the model is mission critical
and gorgeous is the view,
But I'm not being lazy, but sometimes it's just crazy
how much code i write is just glue.
And it wouldn't be so tragic,
but the code ain't doing magic:
it's just moving values through.
And I wish I had a dime
for every single time
I set a TextField's stringValue.

Model View - how we're gonna deep-six all that glue
Model View Controller

Controller's know the Model and View very
uahh - intimately
They often are hardcoding
which is very verboten for reusability.
But now you can connect any value you select
to any view property.
And I think you'll start binding,
then you'll be finding less code in your source tree.
Yeah I know I was astounded,
that's not even a rhyme.

But I think it bares repeating
all the code you won't be needing,
when you hook it up in IB.

Model View - it even handles multiple selections too
Model View Controller

Model View - hope I get my G5 before you
Model View Controller

Yeah, yeah, yeah. Yeah.

I also found a video of James singing it live on WWDC 2003. Here is the video:

Download "Model View Controller" Song

Download this song: model-view-controller song.mp3 (musical geek friday #4)
Downloaded: 40652 times

Download lyrics: model-view-controller lyrics (musical geek friday #4)
Downloaded: 2950

Click to listen:
[audio:http://www.catonmat.net/download/model_view_controller_song.mp3]

Have fun and until next geeky Friday! :)

PS. One of my next posts will be on Design Patterns in Python, so check back! :)

introduction to sqlite database rdbmsIf you have been following my blog, you might have noticed that almost all of my projects use the SQLite database engine.

My projects are relatively tiny, low traffic and data is mostly queried, not written. Such characteristics make SQLite the perfect database for my projects.

If you did not know, the SQLite database is self contained within a single file! There are no configuration woes, no network security to worry about, no hundreds pages of documentation. It's just a single file!

See Distinctive Features of SQLite and Appropriate Uses for SQLite pages to find other points when SQLite is a good fit and when not.

Here is the lecture by Richard Hipp, the author of SQLite:

Here are some interesting facts from the lecture:

  • [02:50] SQLite is designed to be embedded, it's less than 250 KB in size.
  • [08:00] Uncommon SQLite uses (this got me most interested): stand-in for client-server DBMS during testing/debugging. Local database caching. Implementing complex data structures. Sorting large amounts of data. Configuration files. IPC via database. Application file formats.
  • [14:06] SQLite is very convenient to use as a tool to teach basics of SQL, as it just works.
  • [19:32] Unusual features of SQLite: SQLite ignores data types for columns (you can store string in an integer column, for example). SQLite does type affinity on data inserted in columns. Table 'sqlite_master' stores information about tables. Attaching to multiple databases simultaneously via ATTACH command. You can join or copy across multiple open databases (for example, hot backup the database).
  • [24:40] Anatomy of an SQL database engine.
  • [27:00] SQLite compiles queries to byte code (can be viewed via EXPLAIN statement) to be executed in a virtual machine.
  • [28:20] Observations of SQLite: trouble with licensing. A register based virtual machine is much easier to generate code for which is optimal than a stack based VM. Dynamic typing in databases is a really good thing. Regression tests allow rewriting large parts of SQLite without minor version releases.
  • [36:30] Q and A!
  • [36:35] Is there ORM tool available for SQLite?
  • [39:30] How is dynamic typing better than static typing in databases?
  • [41:32] What did you mean by 'complex data types'?
  • [43:15] Why is a register based virtual machine better than a stack based?
  • [44:22] Why does SQLite only parse foreign keys but not enforce them?
  • [46:08] Is SQLite an in-memory database?
  • [46:50] What's the future of SQLite?
  • [48:10] My SQLite DB got corrupt, what do I do?
  • [49:30] When does the DB roll back in case of power failure?
  • [50:30] What happens if there is a second power failure while rolling back the queries from previous power failure?

A few notes from me.

The usage of 'manifest typing' really confused me in this lecture, because I, and most of the people I have talked to, uses this term for 'static typing'. The author of SQLite uses it to mean 'dynamic typing'. Don't know why...

An SQLite database can be managed via the sqlite (or sqlite3) command line tool or GUI tool such as SQLite Browser (primitive), SQLiteSpy (advanced) and SQLite Manager (as a FireFox Add-on).

Finally, here are a few articles you should read if you are interested in more advanced SQLite details:

I hope you enjoyed it and have fun using SQLite for your next project!

This article is part of the article series "Musical Geek Friday."
<- previous article next article ->

musical geek friday - jonathan coulton - code monkeyThis week on Musical Geek Friday we have the Code Monkey song!

This song was written by Jonathan Coulton as a part of his "Thing a Week" musical project, where he would write a new song every week and put it on his website. With this song Jonathan instantly became an Internet Hero. He made it to Slashdot and even New York Times (includes video interview with him)!

This song is about a type of programmers called "Code Monkeys". These programmers do coding without passion, just for money. A person can also be called a code monkey if he's a newbie or he's only able to produce low quality code.

Here it is, the Code Monkey song:

[audio:http://www.catonmat.net/download/code_monkey.mp3]

Download this song: code monkey.mp3 (musical geek friday #3)
Downloaded: 24281 times

Download lyrics: code monkey lyrics (musical geek friday #3)
Downloaded: 3024

Lyrics of the "Code Monkey" song:

Code Monkey get up get coffee
Code Monkey go to job
Code Monkey have boring meeting
With boring manager Rob

Rob say Code Monkey very dilligent
But his output stink
His code not functional or elegant
What do Code Monkey think?

Code Monkey think maybe manager want to write god damned login page himself
Code Monkey not say it out loud
Code Monkey not crazy, just proud
Code Monkey like Fritos
Code Monkey like Tab and Mountain Dew
Code Monkey very simple man
With big warm fuzzy secret heart:
Code Monkey like you
Code Monkey like you, youuuuuuuuuuu

Code Monkey hang around at front desk
Tell you sweater look nice
Code Monkey offer buy you soda
Bring you cup, bring you ice

You say no thank you for the soda cause
Soda make you fat
Anyway you busy with the telephone
No time for chat

Code Monkey have long walk back to cubicle he sit down pretend to work
Code Monkey not thinking so straight
Code Monkey not feeling so great
Code Monkey like Fritos
Code Monkey like Tab and Mountain Dew
Code Monkey very simple man
With big warm fuzzy secret heart:
Code Monkey like you
Code Monkey like you a lot

Code Monkey have every reason
To get out this place
Code Monkey just keep on working
See your soft pretty face
Much rather wake up, eat a coffee cake
Take bath, take nap
This job fulfilling in creative way
Such a load of crap

Code Monkey think someday he have everything even pretty girl like you
Code Monkey just waiting for now
Code Monkey say someday, somehow
Code Monkey like Fritos
Code Monkey like Tab and Mountain Dew
Code Monkey very simple man
With big warm fuzzy secret heart:
Code Monkey like you
Code Monkey like youuuuuuuuuuuuuuuuuu

If you liked it, people on YouTube have posted their videos dancing to this music and even made computer animations for this song. See Code Monkey Videos on YouTube.

Here is my top favorite YouTube video of this song:

Download "Code Monkey" Song

Download this song: code monkey.mp3 (musical geek friday #3)
Downloaded: 24281 times

Download lyrics: code monkey lyrics (musical geek friday #3)
Downloaded: 3024

Click to listen:
[audio:http://www.catonmat.net/download/code_monkey.mp3]

Have fun and until next geeky Friday! :)

coding horror keyword analysisI have subscribed to quite a few programming blogs, one of them being Coding Horror.

Coding Horror is written by a guy named Jeff Atwood (you probably knew that already), and his blog has received massive attention, bringing 93 thousand (woah!) feed subscribers (as of April, 2008).

One thing that caught my attention on CodingHorror blog is that its traffic stats are publicly available!

coding horror traffic statistics

The statistics are hosted by StatCounter.com, which keeps only the last 500 entries of any traffic activity.

recent keyword activity on codinghorror

I wanted to see a clearer picture of the most popular keywords people searched for and ended up in Coding Horror blog.

Thirty minutes later I had written a Perl program, which accessed the statcounter.com statistics, parsed the "Recent Keyword Activity" page, extracted the keywords, and inserted them in an SQLite database.

I always love to describe how my programs work. I'll make it short this time, as we are concentrating on the statistics and not on programming.

The Perl Program

The Perl program uses (or reuses) a few CPAN modules:

The program takes two optional arguments

  • -nodb not to insert the keywords in database (just print them out)
  • number - number of pages to extract keywords from

Here is the source code of the codinghorror_kwstats.pl program:

#!/usr/bin/perl
#
# Peteris Krumins (peter@catonmat.net), 2008
# http://www.catonmat.net  --  good coders code, great reuse
#
# Access codinghorror.com traffic statistics and extract a few pages of latest search queries
# Released under GNU GPL
# 2008.04.08: Version 1.0
#

#
# run it as 'perl codinghorror_kwstats.pl [-nodb] [number of pages to extract]'
# -nodb specifies not to insert keywords in database, just print them to stdout
#

use strict;
use warnings;

use DBI;
use WWW::Mechanize;
use HTML::TreeBuilder;
use Date::Parse;

# URL to publicly available codinghorror's statcounter stats
my $login_url = 'http://my.statcounter.com/project/standard/stats.php?project_id=2600027&guest=1';

# Query used to INSERT a new keyword in the database
my $insert_query = 'INSERT OR IGNORE INTO queries (query, unix_date, human_date) VALUES (?, ?, ?)';

# Path to SQLite database
my $db_path = 'codinghorror.db';

# Insert queries in database or not? Default, yes.
my $do_db = 1;

# Number of pages of keywords to extract. Default 1.
my $pages = 1;

for (@ARGV) {
    $pages = $_ if /^\d+$/;
    $do_db = 0 if /-nodb/;
}

my $dbh;
$dbh = DBI->connect("dbi:SQLite:$db_path", '', '', { RaiseError => 1 }) if $do_db;

my $mech = WWW::Mechanize->new();
my $login_req = $mech->get($login_url);

unless ($mech->success) {
    print STDERR "Failed getting $login_url:\n";
    print $login_req->message, "\n";
    exit 1;
}

unless ($mech->content =~ /Coding Horror/i) {
    # Could not access Coding Horror's stats
    print STDERR "Failed accessing Coding Horror stats\n";
    exit 1;
}

my $kw_req = $mech->follow_link(text => 'Recent Keyword Activity');
unless ($mech->success) {
    print STDERR "Couldn't find 'Recent Keyword Activity' link";
    print $kw_req->message, "\n";
    exit 1;
}

for my $page (1..$pages) {
    my $tree = HTML::TreeBuilder->new_from_content($mech->content);
    my $td_main_panel = $tree->look_down('_tag' => 'td', 'class' => 'mainPanel');
    unless ($td_main_panel) {
        print STDERR "Unable to find '<td class=mainPanel>'";
        exit 1;
    }
    my $table = $td_main_panel->look_down('_tag' => 'table', 'class' => 'standard');
    unless ($table) {
        print STDERR "Unable to find 'table' tag";
        exit 1;
    }
    my @trs = $table->look_down('_tag' => 'tr');
    my $idx = 0;
    for my $tr (@trs) {
        next unless $idx++;
        my @tds = $tr->look_down('_tag' => 'td');
        unless (@tds == 6) {
            print STDERR "<td> count was not 6!\n";
            next;
        }
        my ($date, $time, $query) = map { $_->as_text } (@tds[1..2], $tds[4]);
        next unless $query;
        my $year = (localtime)[5] + 1900;
        my $ydt = "$date $year $time";
        my $unix_date = str2time($ydt);
        print "$date $year $time: $query\n";
        $dbh->do($insert_query, undef, $query, $unix_date, $ydt) if $do_db;
    }
    if ($page != $pages) {
        my $page_req = $mech->follow_link(text => $page + 1);
        unless ($page_req) {
            print STDERR "Couldn't find page ", $page + 1, " of keywords", "\n";
            exit 1;
        }
    }
}

Download: coding horror keyword scraper (downloaded: 2967 times)

Here is an example run of the program:

$ ./codinghorror_kwstats.pl -nodb 2
8 Apr 2008 03:50:54: media player
8 Apr 2008 03:50:53: physical working environment programmers
8 Apr 2008 03:50:26: nano itx case
8 Apr 2008 03:50:23: how to clean some internet spyware or adware infection
8 Apr 2008 03:50:23: mercurial install tutorial windows
8 Apr 2008 03:50:22: iis 5.1 multiple websites
8 Apr 2008 03:50:17: javascript integer manipulation comparision
8 Apr 2008 03:50:16: build machines pc
8 Apr 2008 03:50:14: manage remote desktop connections
8 Apr 2008 03:50:07: check that all variables are initialized
8 Apr 2008 03:50:00: powergrep older version
8 Apr 2008 03:49:43: software counterfeiting
8 Apr 2008 03:48:59: floppy emulator windows xp
8 Apr 2008 03:48:35: safari rendering cleartype
8 Apr 2008 03:48:18: captchas goole broken
8 Apr 2008 03:48:11: vs2005 ide color
8 Apr 2008 03:47:55: optimising dual core for cubase sx3
8 Apr 2008 03:47:44: micosoft project scheduling
8 Apr 2008 03:47:36: dont buy from craig at australian computer resellers
8 Apr 2008 03:47:32: large scale stored procedures
8 Apr 2008 03:47:31: free diff tool
8 Apr 2008 03:46:58: games that support 3 monitors
8 Apr 2008 03:46:56: firefox multiple times same stylesheet
8 Apr 2008 03:46:48: asp.net system.data.sqltypes.sqlnullvalueexception
8 Apr 2008 03:46:37: apple software serial code blocker
8 Apr 2008 03:46:31: beautiful code jon bentley
8 Apr 2008 03:46:28: system.web.httpparseexception
8 Apr 2008 03:46:23: round in c#.net
8 Apr 2008 03:46:15: project postmortem software
8 Apr 2008 03:45:43: programming fun
8 Apr 2008 03:45:33: sending messages over ip using command prompt
8 Apr 2008 03:45:26: where did horror develop?

The SQLite Database

The database has just one table called 'queries' which contains a 'query', 'unix_date' and 'human_date' columns. The 'unix_date' column is used for sorting the entries chronologically, and 'human_date' is there just so I could easily see the date.

Here is the schema of the database:

CREATE TABLE queries (id INTEGER PRIMARY KEY, query TEXT, unix_date INTEGER, human_date TEXT);
CREATE UNIQUE INDEX unique_query_date ON queries (query, unix_date);

As the Perl program is run periodically, it might extract the same keywords several times. I created a UNIQUE index on 'query' and 'unix_date' fields, and left the job to drop the duplicate records to SQLite.

The Perl program uses the following SQL query to insert the data in database:

INSERT OR IGNORE INTO queries (query, unix_date, human_date) VALUES (?, ?, ?)

The 'OR IGNORE' makes sure the duplicate records get silently discarded.

Simple Statistics

I have been collecting keywords since March 31, and the database has now grown to a size of 73'336 records and 7MB (3MB compressed).

Download: coding horror keyword database (.zip) (downloaded: 535 times)

I ran a few simple SQL queries against the data using the GUI SQLite Database Browser to find the most popular keywords. I recommend downloading it, if you want to play around with the database.

The first query selected the 15 most popular keywords, along with their count, and percentage of all keywords.

The following SQL query did it:

SELECT
 count(query) c,
 (round(count(query)/(1.0*(select count(*) from queries)),3)*100) || '%',
 query
FROM queries
GROUP BY query
ORDER BY c DESC
LIMIT 15

most popular coding horror’s keywords (sql query in sqlite database browser)

I also made a bar chart using the public Google Charts API:

This chart would look much better if it had vertical bars. I couldn't figure out how to add keywords nicely below each bar, though.

Here is how the messy query to Google Charts API looks like:

http://chart.apis.google.com/chart?chtt=Coding%20Horror's%20Top%2015%20Keywords&cht=bhs&chd=t:100,77,12.07,10.18,9.09,8.74,8.64,8.49,7.05,6.51,5.91,5.71,5.66,5.61,5.22&chs=400x450&chxt=x,y&chxl=0:|0|2013|1:|command%20prompt%20commands|registration%20keys|cmd%20tricks|vista%20media%20center|sql%20joins|command%20prompt|you%20may%20be%20a%20victim...|codinghorror|dual%20core%20vs%20quad%20core|quad%20core%20vs%20dual%20core|cmd%20commands|command%20prompt%20tricks|system%20idle%20processes|coding%20horror|system%20idea%20process

Just to illustrate various ways to work with SQLite database, I did the same query from command line, and queried top 50 popular keywords, here they are:

$ sqlite3 ./codinghorror.db
sqlite> .header ON
sqlite> .explain ON
sqlite> SELECT count(query) c, query FROM queries GROUP BY query ORDER BY c DESC LIMIT 50;
c     query
----  -------------
2013  system idle process
1550  coding horror
243   system idle processes
205   command prompt tricks
183   cmd commands
176   quad core vs dual core
174   dual core vs quad core
171   codinghorror
142   you may be a victim of software counterfeiting
131   command prompt
119   sql joins
115   vista media center
114   cmd tricks
113   registration keys
105   command prompt commands
105   jeff atwood
99    quad core
96    dell xps m1330 review
89    rainbow tables
84    what is system idle process
82    software counterfeiting
80    fizzbuzz
78    laptop power consumption
77    quad core vs duo core
75    sql join
74    dell xps m1330
74    hard drive temperature
74    vista memory usage
73    source control
70    linked in
69    pontiac aztec
66    pontiac aztek
64    m1330 review
63    cracking
61    consolas
60    captcha
56    hyperterminal
56    ikea jerker
55    code horror
55    polling rate
55    source safe
54    coding horrors
54    dual core or quad core
54    programming quotes
54    visual source safe
53    logparser
51    sourcesafe
51    superfetch
51    three monitors
50    windows experience index

Knowing the most popular keywords can give you some hints what topics to write about on your blog. For example, an article named 'Windows Command Prompt Tricks' would start bringing good traffic from search engines instantly!

I did another bunch of queries to find the most popular programming languages on Coding Horror. I put the languages I could think of in langs.txt file, and ran the following Perl one-liner:

$ perl -MDBI -wlne 'BEGIN { $, = q/ /; $dbh = DBI->connect(q/dbi:SQLite:codinghorror.db/); } print +($dbh->selectrow_array(qq/SELECT count(query) FROM queries WHERE query LIKE "$_" OR query LIKE "$_ %" OR query LIKE "% $_" OR query LIKE "% $_ %"/))[0], $_' langs.txt | sort -n -r

It produced the following output:

1127 visual studio
1087 c#
407 c
287 javascript
239 java
139 asp
104 visual basic
59 php
44 ruby
42 python
26 perl
22 lisp
19 erlang
3 pascal
1 tcl
1 prolog
0 ml
0 haskell

I added 'visual studio' to the list of programming languages, as every beginner thinks it actually is a programming language. There were no keywords matching 'C++' because most search engines think of '+' as an operator rather than a valid search string.

I must say that Python is the answer to life, the universe and everything, as it was searched for 42 times! :)

Here is the same data put on a chart:

Here are some of the most popular search queries among programming languages:

I suggest that you download the keyword database and analyze the data that interests you the most yourself!

Downloads

Download Perl program: coding horror keyword scraper
Downloaded: 2967 times

Download SQLite database(3 MB): coding horror keyword database (.zip)
Downloaded: 535

If you liked the post, why not vote for it?