David McLaughlin Posts Feedhttp://127.0.0.1:8000/feed/Latest thoughts and writings on web development by David McLaughlinSun, 19 May 2013 14:21:45 -0000SSL Client Authentication with Python and pycurlhttp://www.dmclaughlin.com/2011/04/14/ssl-client-authentication-with-python/<p>If you are using Python to make requests over SSL then most likely you'll have run into the limitations of urllib2 if you are using a web service that requires client authentication. I found some recipes that "kind of" solved the problem but didn't bother to check server certificates, which kind of defeats the point if you are using two-way SSL to prevent man-in-the-middle attacks.</p> <p>It was frustrating since most simple things are relatively simple to do in Python. In cURL, two-way SSL verification can be as easy as:</p> <pre class="sh_sh">curl -cacert CA.crt -E client.pem https://myservice.com:443/secure/page</pre> <p>Obviously here we are doing verification with a Certificate Authority we created ourselves. When I vented to a colleague about the difficulty of implementing similar functionality in Python, he wondered why I hadn't bothered using <a href="http://pycurl.sourceforge.net/" mce_href="http://pycurl.sourceforge.net/" target="_blank">pycurl</a>. pycurl is a C-binding and the documentation is not the greatest, nor do the examples explain how to do simple SSL never mind two-way. But after digging around the source, here is one recipe that works:</p> <pre class="sh_python">import pycurl class Response(object): """ utility class to collect the response """ def __init__(self): self.chunks = [] def callback(self, chunk): self.chunks.append(chunk) def content(self): return ''.join(self.chunks) res = Response() curl = pycurl.Curl() curl.setopt(curl.URL, "https://yourservice/path") curl.setopt(curl.WRITEFUNCTION, res.callback) curl.setopt(curl.CAINFO, "/path/to/CA.crt") curl.setopt(curl.SSLCERT, "/path/to/client.pem") curl.perform() print res.content() </pre> <p>And that's it. One other option you might use when testing your SSL implementation with curl is the -k flag, which skips host verification of the server. The option to set in pycurl to do the same is:</p> <pre class="sh_python">curl.setopt(curl.SSL_VERIFYHOST, 0) </pre> <p>Hopefully this saved you digging around the pycurl mailing list and source code like I had to.</p>Looking forward to Berlin Buzzwordshttp://www.dmclaughlin.com/2010/05/13/looking-forward-to-berlin-buzzwords/<p>Just a quick post to point out that a really exciting high-scalability conference is coming to Berlin in June.&nbsp;<a href="http://berlinbuzzwords.de/" target="_blank">Berlin Buzzwords</a>&nbsp;is due to take place on June 7th and 8th and features a variety of talks focusing on free open source software solutions to scalability problems.</p> <p>It is particularly interesting for me because for the last few months I've been experiencing first hand just how many open source technologies have stepped up to the plate in the last few years to make the task of creating distributed and scalable systems accessible, even to mere mortals like myself.&nbsp;</p> <p>Some of the technologies that will be covered are:</p> <p>1) <a href="http://hadoop.apache.org/" target="_blank">Apache Hadoop</a> - an open source version of Google's MapReduce technology, there is almost an entire day of talks dedicated to showcasing the kind of problems Hadoop is a perfect fit for.&nbsp;</p> <p>2) <a href="http://lucene.apache.org/java/docs/" target="_blank">Apache Lucene</a> and <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> - Lucene and Solr are open source search engines built for enterprise-level performance. Solr in particular gives you a whole bunch of distribution and scalability features out of the box and also lets you play with Lucene without needing to get your hands dirty with Java. In the schedule there are talks on doing geosearch and how Lucene aims to make fuzzy searching scalable in the future.</p> <p>3) NoSQL technologies - there are talks on a variety of key-value stores such as <a href="http://cassandra.apache.org/" target="_blank">Apache Cassandra</a>, <a href="http://couchdb.apache.org/" target="_blank">CouchDB</a> and <a href="http://www.mongodb.org/" target="_blank">MongoDB</a> and how to use these technologies for real problems rather than to simply drink the kool-aid.</p> <p>The <a href="http://berlinbuzzwords.de/content/schedule-published" target="_blank">full schedule is online</a>, so if you're in the Berlin area or are just interested in building scalable systems, check out the <a href="http://berlinbuzzwords.de/content/tickets" target="_blank">Berlin Buzzwords ticket page</a>. I will be attending the conference with some of my colleagues at Nokia so if you're coming through for the conference and fancy having a coffee or beer, feel free to drop me a message at david&lt;at&gt;dmclaughlin.com or just send me a message on <a href="http://www.twitter.com/mesadavey" target="_blank">twitter</a>.</p>Chained accessors in Moosehttp://www.dmclaughlin.com/2009/05/15/chained-accessors-in-moose/<p>I've created my second repository on Github - <a href="http://github.com/DavidMcLaughlin/MooseX-ChainedAccessors/tree/master" target="_blank">MooseX::ChainedAccessors</a>. The code is extremely simple, but very powerful: it provide a Moose attribute <a href="http://search.cpan.org/dist/Moose/lib/Moose/Cookbook/Meta/Recipe3.pod" target="_blank">trait</a> that allows you to method chain via write operations on your accessor methods. If you already know what this means and just want to grab the code, then you can do so from the github <a href="http://github.com/DavidMcLaughlin/MooseX-ChainedAccessors/downloads" target="_blank">download page</a> (I'm still waiting on my CPAN account being set up before I can upload it there).</p> <h3>Method chaining</h3> <p>Method chaining is a simple yet powerful way of creating concise APIs for objects which have lots of small, individual operations where we don't need to know about the return value. One of the most popular examples of method chaining in action is in the jQuery API:</p> <pre class="sh_javascript">var $mydiv = $('#my-div');<br />$mydiv.html('hello, world!');<br />$mydiv.slideUp();<br /><br />// becomes...<br /><br />$('#my-div').html('hello, world!').slideUp();<br /></pre> <p>To achieve this, a new jQuery object is created and returned by the selector query and then each subsequent method call returns that same object. For example, a crude version of <code>html</code> might look like:</p> <pre class="sh_javascript">function html(html_as_str)<br />{<br /> this.innerHTML = html_as_str;<br /> return this;<br />}<br /></pre> <p>And that one line - <code>return this</code> - is all there is to it. Regardless of the language, OO method chaining is achieved in the same way: in PHP it would be <code>return $this</code>, in Python <code>return self</code>, in Perl <code>return $self</code>, etc.</p> <h3>Accessor chaining</h3> <p>If method chaining is as simple as that, then adding chaining to accessors (methods which abstract read/write operations on class attributes) will be as simple as adding <code>return $self</code> to the end of write accessors. This is easy if you're manually writing your accessors, but Moose handles accessor creation for you using the <code>has</code> sugar subroutine. If you want method chaining on accessors, you'll need to write those accessors yourself - or extend Moose.</p> <p>Why go to all the trouble? Well, the driving case for me was that I had created a Moose role which allowed me to display debug info on a per-instance basis. A simplified version of this Role is:</p> <pre class="sh_perl">package MyApp::Roles::Debug;<br />use Moose::Role;<br /><br />has 'debug' =&gt; (<br /> is =&gt; 'rw',<br /> isa =&gt; 'Bool',<br /> default =&gt; sub { return 0; },<br />);<br /><br />sub debug_message<br />{<br /> my ($self, $message) = @_;<br /> print $message . "\n" if $self-&gt;debug;<br />}<br /><br />1;<br /></pre> <p>This allowed me to attach my role to any complex class which required debugging when tests failed or strange things happened and I wanted an overview of what was happening. Typical usage was:</p> <pre class="sh_perl">package MyApp::Model;<br />use Moose::Role;<br /><br />with 'MyApp:Roles::Debug';<br /><br />sub complex_method<br />{<br /> my $self = shift;<br /><br /> # complex stuff in here.. lots of potential to go wrong<br /> $self-&gt;debug_message("Here is some info about the current state");<br /> # more complex stuff<br /> return;<br />}<br /><br /><br />my $model = MyApp::Model-&gt;new(debug =&gt; 1);<br />$model-&gt;complex_method(); <br /></pre> <p>This worked fine, until I started trying to use this role with some of the APIs I had designed that took full advantage of method chaining and composition. In a <a href="../../../../2009/04/19/ugly-perl-a-lesson-in-the-importance-of-api-design" target="_blank">previous post</a> I showed some code from the Sugar::ORM project I'm currently working on. Well, the query interface (which is heavily based on the Django ORM) for that ORM looks like this:</p> <pre class="sh_perl">my @model_objs = Model-&gt;query-&gt;filter(name__like =&gt; 'Example%');<br /></pre> <p>The call to Model-&gt;query returns a <code>Sugar::ORM::ResultSet</code> instance which has a bunch of methods like <code>filter</code>, <code>exclude</code>, <code>order_by</code> and <code>load_related</code> which <code>return $self</code> unless called in list context. This allows us to build up complex filters based on criteria (like a query string from a GET request) or apply sorting and pagination all in one nice line:</p> <pre class="sh_perl">my @bands = Band-&gt;query-&gt;filter(genre__name =&gt; 'Rock')-&gt;order_by(name =&gt; 'ASC');<br /><br /># OR<br /><br />my $query = Band-&gt;query-&gt;filter(events__date__gte =&gt; $now);<br />if(my @genres = CGI-&gt;param('genre'))<br />{<br /> $query-&gt;filter(genre__id__in =&gt; [@genres]); <br />}<br />if(my $location = CGI-&gt;param('location'))<br />{<br /> $query-&gt;filter(location__name =&gt; $location);<br />}<br />if(my $order_by = CGI-&gt;param('sort'))<br />{<br /> $query-&gt;order_by(name =&gt; 'ASC');<br />}<br />my @bands = $query-&gt;limit(10);<br /></pre> <p>In practice this has work really well, but an ORM is a fairly complex code base so there have been many edge cases that have led to subtle bugs. This has meant a lot of debugging to be done deep down in the ORM engine classes. I can add my debugging role to my <code>ResultSet</code> class but to turn on debugging on has meant splitting up the chained filters in test scripts:</p> <pre class="sh_perl">my @results = Band-&gt;query-&gt;filter(genre__name =&gt; 'Rock')-&gt;order_by(name =&gt; 'ASC');<br /><br /># becomes...<br /><br />my $query = Band-&gt;query-&gt;filter(genre__name =&gt; 'Rock');<br />$query-&gt;debug(1);<br />my @results = $query-&gt;order_by(name =&gt; 'ASC');</pre> <p>This quickly became tedious, what I really wanted to do was set my attribute without breaking the chain.</p> <h3>MooseX::ChainedAccessors<br /></h3> <p>Now, there are a couple of other ways I could have solved this problem: debug could have been passed into the call to <code>Model-&gt;query</code> or the<code> debug</code> attribute in my Role could have been changed to a method which set up chaining. But both solutions would have to be repeated any time I wanted chained accessors in the future. In the spirit of DRY, I wanted a more elegant and easier to implement solution. After a quick glance at the Moose docs and long look at how <code>has</code> works in Moose, the <code>Chained</code> trait was born. The <code>debug</code> attribute in my Role now needed one extra line:</p> <pre class="sh_perl">package MyApp::Roles::Debug;<br />use Moose::Role;<br /><br />has 'debug' =&gt;<br />(<br /> traits =&gt; ['Chained'],<br /> is =&gt; 'rw',<br /> isa =&gt; 'Bool',<br /> default =&gt; sub { 0; },<br />);<br /><br /># .. etc.<br /></pre> <p>And I could now debug my ORM queries with one simple change:</p> <pre class="sh_perl">Band-&gt;query-&gt;load_related-&gt;get(name =&gt; 'Mesa Verde');<br /><br /># becomes ...<br /><br />Band-&gt;query-&gt;debug(1)-&gt;load_related-&gt;get(name =&gt; 'Mesa Verde');<br /></pre> <p>And that's all there is to it.</p> <h3>Installing</h3> <p>The package isn't on CPAN yet, so in the meantime you can install it manually by <a href="http://github.com/DavidMcLaughlin/MooseX-ChainedAccessors/downloads" target="_blank">downloading from github</a>, unpacking the tar into a temporary directory and running these commands:</p> <pre>perl Makefile.PL<br />make test<br />make install</pre> <p>That's it. The only dependency is, of course, <a href="http://search.cpan.org/dist/Moose/" target="_blank">Moose</a>. Oh, and <a href="http://search.cpan.org/dist/Module-Install/" target="_blank">Module::Install</a> (thanks Tim).</p>Progressive enhancement with PerlTemplateshttp://www.dmclaughlin.com/2009/04/26/introducing-perltemplates/<p>I've just created my first repository on <a href="http://github.com/" target="_blank">github</a>: <a href="http://github.com/DavidMcLaughlin/PerlTemplates/tree/master" target="_blank">PerlTemplates</a>. PerlTemplates is a JavaScript template engine which uses the same syntax as the Perl template engine <a href="http://search.cpan.org/dist/HTML-Template/" target="_blank">HTML::Template</a>. Why would you need something like this?</p> <p>Well hopefully you are aware of the importance of <a href="http://en.wikipedia.org/wiki/Progressive_enhancement" target="_blank">progessive enhancement</a>; and if, like me, you work on web applications where you just can't ignore those who have disabled JavaScript in their browsers then you'll also be aware of the banality of creating both JavaScript and non-JavaScript versions of your slick AJAX interfaces.</p> <p>Some of the common ways of getting round this that I've seen from other developers have been to return HTML (as opposed to returning XML or JSON) and inject that directly into the DOM, or to create the DOM elements in the Javascript code itself. Both methods have their drawbacks: as soon as you've got HTML creation in the Javascript code you now need to maintain markup in two seperare locations. Returning HTML doesn't have this problem, but for complex situations you rarely want just presentation back - you need data.</p> <p>Using PerlTemplates has allowed us to follow the principles of DRY, and it has made progressive enhancement quick and simple. To illustrate, the 'output' of a search results script (which is a prime candidate for AJAXification) might look like this:</p> <pre class="sh_perl"> <br />my $template = HTML::Template-&gt;new('/path/to/search/results.tmpl');<br />$template-&gt;param(%values); # where values contains the template data structure<br />print CGI-&gt;header, $template-&gt;output();<br /></pre> <p>Well, to make it PerlTemplates-ready, we simply add a condition which returns JSON in the event of an AJAX request (which can be detected in various different ways):</p> <pre class="sh_perl">if($ajax_request)<br />{<br /> print CGI-&gt;header, JSON-&gt;new-&gt;encode(%values); <br />}<br />else<br />{<br /> my $template = HTML::Template-&gt;new('/path/to/search/results.tmpl');<br /> $template-&gt;param(%values);<br /> print CGI-&gt;header, $template-&gt;output();<br />}<br /></pre> <p>Then in our Javascript, we have code that looks like this (using jQuery):</p> <pre class="sh_perl">$.getJSON('/search/results', function(json_data) {<br /> var tmpl = new PerlTemplates({url:'results.tmpl', data: json_data, target: 'search-results'});<br /> tmpl.render();<br />}<br /></pre> <p>That's all there is to it. The one drawback to this approach is that your templates must be made available over HTTP, which might be tricky if your templates are stored outside of your root web directory (or you're a fan of security by obscurity).</p> <h3>Download</h3> <p>PerlTemplates has no dependencies and the minified version comes in at just over 5kb. You can see it in action <a href="../../../../ui/js/perl-templates/demo.html" target="_blank" title="PerlTemplates demo">here</a> and download the package from <a href="../../../../ui/js/perl-templates.zip" target="_blank" title="download PerlTemplates">here</a>. PerlTemplates has been tested in all major browsers, and is currently in use on sites serving millions of pages per month.</p>Ugly Perl: A lesson in the importance of API designhttp://www.dmclaughlin.com/2009/04/19/ugly-perl-a-lesson-in-the-importance-of-api-design/<p>One of the most challenging aspects of my role as a Software Architect has been trying to standardise our development practices in a language as flexible as Perl. Powered by the culture of There is More Than One Way to Do It and a previous lack of technical leadership, we have ended up in a situation where almost every conceivable style of code has been utilised across all of our different mod_perl web applications. It's a maintenance nightmare.</p> <p>Last year I started to turn that around by advocating object oriented programming and model view controller architecture using modern Perl techniques powered by <a href="http://search.cpan.org/~drolsky/Moose-0.74/lib/Moose.pm" target="_blank">Moose</a>. Something I noticed though when we sat down and evaluated the state of our code was that some of the easiest and most reliable systems we had were the procedural ones, and by far the most painful systems to work with on a daily basis were those where the lead developer had went on an architectural expedition and built a tightly-coupled OOP monstrosity.</p> <p>What we took away from that evaluation process is that, more than choice of programming language, more than choice of development paradigm and more than choice of development methodology, good API design is the single most important factor in how developers perceive the quality of code. Introducing the code review process to our team only confirmed this: almost every review I've taken part in has revolved around naming conventions and style rather than performance or implementation.</p> <p>And it's no coincidence that by focussing less on concepts like OOP and MVC and more on creating good APIs, we've really started to turn the corner in the land of maintenance programming.</p> <h2>API in action: jQuery</h2> <p>One of the best examples of the impact a good API on a language is in the Javascript framework community. When jQuery launched, it was a textbook case of reinventing the wheel. It was slower than most of the competitors, had less features and there was no community that compared with the following that YUI and Prototype had built up. Yet somehow it still managed to muscle its way into becoming synonymous with web 2.0.</p> <pre class="sh_javascript">$('#my-link').click(function(e) { <br />&nbsp;&nbsp;&nbsp; $('#content').addClass('active').slideUp();<br />});</pre> <p>The secret to its success was in the only area where it introduced something new: the slick and concise CSS selector API. No new functionality, no performance benefits, the selling point from <a href="http://web.archive.org/web/20060203025710/http:/jquery.com/" target="_blank">day one</a> of jQuery has been "designed to change the way that you write Javascript." And people really bought into it.</p> <p>jQuery really is a great example of how a solid framework API can turn around the whole perception of working with a language. Three years ago Javascript had a nasty reputation of being frustrating and difficult to work with, these days whether it's jQuery or Dojo or MooTools, the elegant APIs of the most popular frameworks more often than not make it a pleasure.</p> <h2>The Perl ORM problem</h2> <p>The motivation for this post came when I started to look for a Perl ORM solution to adopt for our MVC development. Moving away from Perl would have been too extreme and unrealistic a step, as we were going for slow and gradual refactoring of each system. So when I looked at the two most frequently discussed Perl solutions, <a href="http://search.cpan.org/dist/DBIx-Class/" target="_blank">DBIx::Class</a> and <a href="http://search.cpan.org/dist/Rose-DB-Object/" target="_blank">Rose::DB::Object</a>, what I saw was more than a little disappointing.</p> <p>As a team we quickly came to the conclusion that it might be best to roll our own. Most of us had used the likes of <a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html" target="_blank">ActiveRecord</a>, the <a href="http://docs.djangoproject.com/en/dev/topics/db/models/#topics-db-models" target="_blank">Django ORM</a> and <a href="http://www.sqlalchemy.org/" target="_blank">SQL Alchemy</a> from the Ruby and Python communities, so we definitely felt like the syntax of an ORM could be a lot better than what we were seeing. When I mentioned in #moose a few months back that I was thinking of writing my own ORM, I was mocked quite heavily and pointed in the direction of <a href="http://search.cpan.org/dist/Fey-ORM/" target="_blank">Fey::ORM</a>. Again, looking at the code all I could think of was that the standard was nowhere near what I had seen from other solutions.</p> <p>In particular, I really liked using the Django ORM. I used Django to build this blog, as well as a few other personal projects and the syntax seemed to gracefully scale and handle almost all of the nasty edge cases. Trying to describe how it felt moving from the Django ORM to DBIx::Class is best illustrated with an example. The following models are directly from the <a href="http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class/Manual/Example.pod" target="_blank">DBIx::Class tutorial</a> on CPAN.</p> <pre class="sh_perl">package MyDatabase::Main;<br />use base qw/DBIx::Class::Schema/;<br />__PACKAGE__-&gt;load_namespaces;<br /><br />1;<br /><br />package MyDatabase::Main::Result::Artist;<br />use base qw/DBIx::Class/;<br />__PACKAGE__-&gt;load_components(qw/PK::Auto Core/);<br />__PACKAGE__-&gt;table('artist');<br />__PACKAGE__-&gt;add_columns(qw/ artistid name /);<br />__PACKAGE__-&gt;set_primary_key('artistid');<br />__PACKAGE__-&gt;has_many('cds' =&gt; 'MyDatabase::Main::Result::Cd');<br />1;<br /><br />package MyDatabase::Main::Result::Cd;<br />use base qw/DBIx::Class/;<br />__PACKAGE__-&gt;load_components(qw/PK::Auto Core/);<br />__PACKAGE__-&gt;table('cd');<br />__PACKAGE__-&gt;add_columns(qw/ cdid artist title/);<br />__PACKAGE__-&gt;set_primary_key('cdid');<br />__PACKAGE__-&gt;belongs_to('artist' =&gt; 'MyDatabase::Main::Result::Artist');<br />__PACKAGE__-&gt;has_many('tracks' =&gt; 'MyDatabase::Main::Result::Track');<br />1;<br /><br />package MyDatabase::Main::Result::Track;<br />use base qw/DBIx::Class/;<br />__PACKAGE__-&gt;load_components(qw/PK::Auto Core/);<br />__PACKAGE__-&gt;table('track');<br />__PACKAGE__-&gt;add_columns(qw/ trackid cd title/);<br />__PACKAGE__-&gt;set_primary_key('trackid');<br />__PACKAGE__-&gt;belongs_to('cd' =&gt; 'MyDatabase::Main::Result::Cd');<br />1;</pre> <p>The repetition of the Perl special variable __PACKAGE__ immediately stands out, but the rest isn't too bad. For me though, the django equivalent is far superior:</p> <pre class="sh_python">from django.db import models<br /><br />class Artist(models.Model):<br />&nbsp; artistid = models.AutoField(primary_key = True)<br />&nbsp; name = models.CharField()<br /><br />class Cd(models.Model):<br />&nbsp; cdid&nbsp;&nbsp; = models.AutoField(primary_key = True)<br />&nbsp; title&nbsp; = models.CharField()<br />&nbsp; year&nbsp;&nbsp; = models.YearField()<br />&nbsp; artist = models.ForeignKey(Artist)<br /><br />class Track(models.Model):<br />&nbsp; trackid = models.AutoField(primary_key = True)<br />&nbsp; title&nbsp;&nbsp; = models.CharField()<br />&nbsp; cd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = models.ForeignKey(Cd)</pre> <p>The first thing that stands out about the django syntax is that it very similar to what it represents: the definition of a SQL table. In fact, the nature of the django model definition is that you provide all the information required to actually run a <code>CREATE TABLE</code> command if you need to. In one lean Python class we have everything we need to know about our model. <br /><br />A notable difference between the two packages is in the way they handle the bidirectional ForeignKey relationship: you only have to define them once in Django, whereas in DBIx::Class you need to define both directions separately. You could argue that in DBIx::Class this is intentional for readability &ndash; when you load up each model you see all of that model's relationships inside its own package &ndash; but in real, complex systems this would actually lead to major model definition bloat.</p> <p>When it comes to querying these models, the design gap is even more apparent. The DBIx::Class tutorial has this as example CRUD code:</p> <pre class="sh_perl">&nbsp; my $schema = MyDatabase::Main-&gt;connect('dbi:SQLite:db/example.db');<br /><br />&nbsp; my @artists = (['Michael Jackson'], ['Eminem']);<br />&nbsp; $schema-&gt;populate('Artist', [<br />&nbsp;&nbsp;&nbsp;&nbsp; [qw/name/],<br />&nbsp;&nbsp;&nbsp;&nbsp; @artists,<br />&nbsp; ]);<br /><br />&nbsp; my %albums = (<br />&nbsp;&nbsp;&nbsp; 'Thriller' =&gt; 'Michael Jackson',<br />&nbsp;&nbsp;&nbsp; 'Bad' =&gt; 'Michael Jackson',<br />&nbsp;&nbsp;&nbsp; 'The Marshall Mathers LP' =&gt; 'Eminem',<br />&nbsp; );<br /><br />&nbsp; my @cds;<br />&nbsp; foreach my $lp (keys %albums) {<br />&nbsp;&nbsp;&nbsp; my $artist = $schema-&gt;resultset('Artist')-&gt;search({<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name =&gt; $albums{$lp}<br />&nbsp;&nbsp;&nbsp; });<br />&nbsp;&nbsp;&nbsp; push @cds, [$lp, $artist-&gt;first];<br />&nbsp; }<br /><br />&nbsp; $schema-&gt;populate('Cd', [<br />&nbsp;&nbsp;&nbsp; [qw/title artist/],<br />&nbsp;&nbsp;&nbsp; @cds,<br />&nbsp; ]);<br /><br /><br />&nbsp; my %tracks = (<br />&nbsp;&nbsp;&nbsp; 'Beat It'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; 'Thriller',<br />&nbsp;&nbsp;&nbsp; 'Billie Jean'&nbsp;&nbsp;&nbsp;&nbsp; =&gt; 'Thriller',<br />&nbsp;&nbsp;&nbsp; 'Dirty Diana'&nbsp;&nbsp;&nbsp;&nbsp; =&gt; 'Bad',<br />&nbsp;&nbsp;&nbsp; 'Smooth Criminal' =&gt; 'Bad',<br />&nbsp;&nbsp;&nbsp; 'Leave Me Alone'&nbsp; =&gt; 'Bad',<br />&nbsp;&nbsp;&nbsp; 'Stan'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; 'The Marshall Mathers LP',<br />&nbsp;&nbsp;&nbsp; 'The Way I Am'&nbsp;&nbsp;&nbsp; =&gt; 'The Marshall Mathers LP',<br />&nbsp; );<br /><br />&nbsp; my @tracks;<br />&nbsp; foreach my $track (keys %tracks) {<br />&nbsp;&nbsp;&nbsp; my $cdname = $schema-&gt;resultset('Cd')-&gt;search({<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; title =&gt; $tracks{$track},<br />&nbsp;&nbsp;&nbsp; });<br />&nbsp;&nbsp;&nbsp; push @tracks, [$cdname-&gt;first, $track];<br />&nbsp; }<br /><br />&nbsp; $schema-&gt;populate('Track',[<br />&nbsp;&nbsp;&nbsp; [qw/cd title/],<br />&nbsp;&nbsp;&nbsp; @tracks,<br />&nbsp; ]);</pre> <p>Even though I know what they're trying to achieve here, looking at the code it still confuses me as to why they need to search a result set to connect these models together. Once again, when compared to the equivalent django API, the difference speaks for itself:</p> <pre class="sh_python">&nbsp; from myapp.models import Artists, Albums, Tracks;<br />&nbsp; <br />&nbsp; mj = Artists.create(name = 'Michael Jackson);<br />&nbsp; eminem = Artists.create(name = 'Eminem')<br /><br />&nbsp; thriller = Albums.create(title = 'Thriller', artist = mj)<br />&nbsp; bad = Albums.create(title = 'Bad', artist = mj)<br />&nbsp; themmlp = Albums.create(title = 'The Marshall Mathers LP', artist = eminem)<br />&nbsp; Tracks.create(title = 'Beat It', album = thriller)<br />&nbsp; Tracks.create(title = 'Billie Jean', album = thriller)<br />&nbsp; Tracks.create(title = 'Dirty Diana', album = bad)<br />&nbsp; Tracks.create(title = 'Smooth Criminal', album = bad)<br />&nbsp; Tracks.create(title = 'Leave Me Alone', album = bad)<br />&nbsp; Tracks.create(title = 'Stan', album = themmlp)<br />&nbsp; Tracks.create(title = 'The Way I Am', album = themmlp)</pre> <p>Simple, clean and self-documenting.</p> <p>Singling out DBIx::Class might also seem a little snide, but I really don't like sitting here criticising open source code. DBIx::Class solves a difficult problem and the authors have contributed far more to the Perl and open source communities than I have. The library is also over four years old and has had to maintain backwards compatability throughout that time. The original designer might have solved the ORM problem differently today.</p> <p>Still, the state of affairs is that the elegant and evolving solutions in other languages are exactly what the Perl community wants to compete with. When I read posts like <a href="http://www.catalyzed.org/2009/04/perl-is-dead-long-live-perl.html" target="_blank">this one</a> claiming that Catalyst and DBIx::Class are a demonstration of what Perl can do in 2009 I can only think that a lot of these guys are missing the point. Competing against feature sets just isn't enough anymore: frameworks like jQuery, Rails and Django have set the expectation - developers want clean APIs. And the frustrating thing is that Perl is the perfect language to deliver them.</p> <h2>Modern Perl Case Study: Sugar ORM</h2> <p>To illustrate the point (and so those whose code I've criticised can tear me a new one back!), I'll show you what my own solution to the ORM problem has been. Let's reuse the same tables as before and create a new interface with the help of Moose sugar. <br /><br /><strong>Model definitions:</strong></p> <pre class="sh_perl">package models::base;<br />use base 'ORM::Table';<br /><br />__PACKAGE__-&gt;add_connection(username =&gt; 'david', password =&gt; 'thdnsn484');<br /><br />package models::artists;<br />use Sugar::ORM;<br />extends 'models::base';<br /><br />field 'artistid' =&gt; (type =&gt; 'Int', primary_key =&gt; 1);<br />field 'name'&nbsp;&nbsp;&nbsp;&nbsp; =&gt; (type =&gt; 'Int');<br />1;<br /><br />package models::cds;<br />use Sugar::ORM;<br />extends 'models::base';<br /><br />field 'cdid'&nbsp; =&gt; (type =&gt; 'Int', primary_key =&gt; 1);<br />field 'title' =&gt; (type =&gt; 'Char');<br />foreign_key 'artist' =&gt; (through =&gt; 'models::artist', reverse =&gt; 'albums');<br />1;<br /><br />package models::tracks;<br />use Sugar::ORM;<br />extends 'models::base';<br /><br />field 'trackid' =&gt; (type =&gt; 'Int', primary_key =&gt; 1);<br />field 'title'&nbsp;&nbsp; =&gt; (type =&gt; 'Char');<br />foreign_key 'album' =&gt; (through =&gt; 'models::cd');<br />1;</pre> <p><strong>CRUD operations:</strong></p> <pre class="sh_perl">use aliased 'models::artists' =&gt; 'Artist';<br />use aliased 'models::cds' =&gt; 'Album';<br />use aliased 'models::tracks' =&gt; 'Song';<br /><br />my $mj = Artist-&gt;create(name =&gt; 'Michael Jackson');<br />my $eminem = Artist-&gt;create(name =&gt; 'Eminem');<br /><br />my $thriller = Album-&gt;create(title =&gt; 'Thriller', artist =&gt; $mj);<br />my $bad = Album-&gt;create(title =&gt; 'Bad', artist =&gt; $mj);<br />my $themmlp = Album-&gt;create(title =&gt; 'The Marshall Mathers LP', artist =&gt; $eminem);<br /><br />Song-&gt;create(title =&gt;'Beat It', album =&gt; $thriller);<br />Song-&gt;create(title =&gt; 'Billie Jean', album =&gt; $thriller);<br />Song-&gt;create(title =&gt; 'Dirty Diana', album =&gt; $bad);<br />Song-&gt;create(title =&gt; 'Smooth Criminal', album =&gt; $bad);<br />Song-&gt;create(title =&gt; 'Leave Me Alone', album =&gt; $bad);<br />Song-&gt;create(title =&gt; 'Stan', album =&gt; $themmlp);<br />Song-&gt;create(title =&gt; 'The Way I Am', album =&gt; $themmlp);<br /><br />And, as a bonus some extra code to traverse the relationships:<br /><br />for my $artist ($mj, $eminem)<br />{<br />&nbsp;&nbsp;&nbsp; say $artist-&gt;name;<br />&nbsp;&nbsp;&nbsp; for my $album ($artist-&gt;albums)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; say $album-&gt;title;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; say join ',', $album-&gt;tracks;<br />&nbsp;&nbsp;&nbsp; }<br />}</pre> <p><strong>Design Explanation</strong><br /><br /> One of the reasons the Django model definition is so much trimmer than DBIx::Class is because Python supports shared class data natively and Perl doesn't. This is important for our models' performance because you only want to load up the fields and relationships once at compile time rather than at each object instantiation. To compensate, Sugar::ORM models are just Moose classes that use <a href="http://search.cpan.org/~drolsky/Moose-0.74/lib/Moose/Exporter.pm" target="_blank">Moose::Exporter</a> to add <code>table</code>, <code>field</code>, <code>foreign_key</code> and <code>many_to_many</code> to the package namespace. Each one of those subroutines in turn stores information about the model as metadata at compile time.</p> <p>One key difference from django is that you have to define a base class to provide database connectivity, this could just as easily be refactored using <a href="http://search.cpan.org/~drolsky/Moose-0.74/lib/Moose/Role.pm" target="_blank">roles</a>. This decision was made because of how tightly coupled to the Django web environment the ORM is. If you want to access your models outside of a Django web request, like in a cron script, then you have a bit of leg work to do to set up the django environment. To avoid this and decouple the ORM entirely from the web, all configuration for the ORM talking to the database is completely self-contained.</p> <p>Since the sample models here are pretty basic, here is a more complex one to illustrate how Sugar::ORM handles some common edge cases (of package names not matching the table name or foreign key field names being different from the primary key of the table they relate to, etc.):</p> <pre class="sh_perl">package blog::models::posts;<br />use Sugar::ORM;<br />extends 'model::base';<br /><br />table 'blogposts'; <br />field 'id'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; (type =&gt; 'Int', primary_key =&gt; 1);<br />field 'title'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; (type =&gt; 'Char', max_length =&gt; 128, required =&gt; 1);<br />field 'slug'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; (type =&gt; 'Slug', from =&gt; 'title');<br />field 'datetime_posted'&nbsp; =&gt; (type =&gt; 'DateTime', auto_on_add =&gt; 1);<br />field 'datetime_updated' =&gt; (type =&gt; 'DateTime', auto_now =&gt; 1);<br />field 'post'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; (type =&gt; 'Text', required =&gt; 1);<br />foreign_key 'author'&nbsp;&nbsp;&nbsp;&nbsp; =&gt; (from =&gt; 'added_by_id', through =&gt; 'blog::models::user');<br />many_to_many 'tags'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; (through =&gt; 'blog::models::tags', using =&gt; 'blogposts_tags');<br />has 'something_extra'&nbsp;&nbsp;&nbsp; =&gt; (is&nbsp; =&gt; 'rw', isa =&gt; 'Bool', default =&gt; sub { 0; });<br /><br />sub permalink <br />{<br />&nbsp;&nbsp;&nbsp; my $self = shift;<br />&nbsp;&nbsp;&nbsp; return sprint("/post/%s", $self-&gt;slug);<br />}</pre> <p>The equivalent model in Django would be:</p> <pre class="sh_python">class Posts(models.Model):<br />&nbsp;&nbsp;&nbsp; title&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = models.CharField(max_length = 128, required = 1)<br />&nbsp;&nbsp;&nbsp; slug&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = models.SlugField(max_length = 128)<br />&nbsp;&nbsp;&nbsp; datetime_posted&nbsp; = models.DateTimeField(auto_on_add = 1)<br />&nbsp;&nbsp;&nbsp; datetime_updated = models.DateTimeField(auto_now = 1)<br />&nbsp;&nbsp;&nbsp; post&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = models.TextField(required = 1)<br />&nbsp;&nbsp;&nbsp; added_by&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = models.ForeignKey(User, rel_name = 'author')<br />&nbsp;&nbsp;&nbsp; tags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = models.ManyToManyField(Tag)<br />&nbsp;&nbsp;&nbsp; something_extra&nbsp; = None<br /><br />&nbsp;&nbsp;&nbsp; def permalink(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return "/post/%s" % self.slug<br />&nbsp;&nbsp;&nbsp; class Meta:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; db_table = 'blogposts'</pre> <p>When you compare the two, there is very little difference in terms of readability except perhaps the symbol bloat in the Perl version. But what is interesting is that the DBIx::Class version is actually much trimmer because of how little information is stored about columns:</p> <pre class="sh_perl">package MyDatabase::Main::Result::Posts;<br />use base qw/DBIx::Class/;<br />__PACKAGE__-&gt;load_components(qw/PK::Auto Core/);<br />__PACKAGE__-&gt;table('blogposts');<br />__PACKAGE__-&gt;add_columns(qw/ id title slug datetime_posted datetime_updated post /);<br />__PACKAGE__-&gt;set_primary_key('id');<br />__PACKAGE__-&gt;belongs_to('author' =&gt; 'MyDatabase::Main::Result::User');<br />__PACKAGE__-&gt;many_to_many('tags' =&gt; 'blogposts_tags', 'post');<br /><br /></pre> <p>This is a good example of why conciseness isn't everything.&nbsp; With Django and Sugar::ORM, everything you'd need to know about the SQL table is stored in the model &ndash; that way to understand the models all you need to do is read the code. With DBIx::Class I suspect there would be a whole load of DESC `table` commands at the RDBMS command line.&nbsp; Plus, by storing the field types in the model code you can also do useful things later, like add data integrity checks during CRUD operations.</p> <p>Of course neither the django ORM nor Sugar::ORM are perfect, and with something non-deterministic like this there will always be some people who prefer the DBIx code. Putting that to one side, what I've tried to demonstrate with my API design is that Perl is incredibly flexible. If it has a reputation as being ugly, then all that says is that the Perl community has been writing ugly APIs.</p> <p>&nbsp;</p> <h2>Enter the beauty contest<br /></h2> <p>The good news for Perl is that one of the major causes of all the bad code out there, its flexibility, also makes it one of the most powerful languages around for creating amazing APIs with. Armed with Moose and tools like Moose::Exporter and <a href="http://search.cpan.org/dist/MooseX-Declare/lib/MooseX/Declare.pm" target="_blank">MooseX::Declare</a>, there is no limit to the elegant and clean Perl code that we could all be writing.</p> <p>The community definitely has the talent, which is why it would be such a shame if Perl lost out in the beauty contest. But if the Perl community is really serious about a modern Perl rennaisance, then there is a very real need to get serious about API design.</p> <p>&nbsp;</p> <p>&nbsp;</p> <h3>Update:</h3> <p><a href="http://perl-signals.tumblr.com/" target="_blank">Jess Robinson</a> pointed out that the DBIx::Class tutorial I used was not the most elegant way to use the API. Her updated code adds field types to the model definition as well as provides a much cleaner insertion API:</p> <pre class="sh_perl"><p>package MyDatabase::Main::Result::Artist;<br />use base qw/DBIx::Class/;<br />__PACKAGE__-&gt;load_components(qw/PK::Auto Core/);<br />__PACKAGE__-&gt;table('artist');<br />__PACKAGE__ -&gt;add_columns(<br /> artistid =&gt; {<br /> data_type =&gt; 'integer',<br /> is_auto_increment =&gt; 1,<br /> },<br /> name =&gt; {<br /> data_type =&gt; 'varchar',<br /> size =&gt; 255,<br /> }<br />);<br />__PACKAGE__-&gt;set_primary_key('artistid');<br />__PACKAGE__-&gt;has_many('cds' =&gt; 'MyDatabase::Main::Result::Cd');<br />1;</p><p>&nbsp;</p><p>my $schema = MyDatabase::Main-&gt;connect('dbi:SQLite:db/example.db');<br /><br />my $mj = $schema-&gt;create({ name =&gt; 'Michael Jackson' });<br />my $eminem = $schema-&gt;resultset('Artist')-&gt;create({ name =&gt; 'Eninem' });<br /><br />my $thriller = $schema-&gt;resultset('Album')-&gt;create({<br /> artist =&gt; $mj,<br /> title =&gt; 'Thriller',<br />});</p><p>my $bad = $schema-&gt;resultset('Album')-&gt;create({<br /> artist =&gt; $mj,<br /> title =&gt; 'Bad',<br />});</p><p>my $themmlp = $schema-&gt;resultset('Album')-&gt;create({<br /> artist =&gt; $eninem,<br /> title =&gt; 'The Marshall Mathers LP',<br />});<br /><br />$schema-&gt;resultset('Track')-&gt;create({ title =&gt; 'Beat Id', album =&gt; $thriller })</p></pre> <p>Clearly the original comparison I made was a case of apples and oranges as <code>populate</code> in the DBIx::Class API is actually a multi-insert interface which django doesn't provide. It's also clear from this example now that <code>resultset</code> selects the name of the model to work with. Perhaps this illustrates that good documentation is just as important as a sexy API.</p>How I learnt to love Perlhttp://www.dmclaughlin.com/2008/12/07/how-i-learnt-to-love-perl/<p>I love the <a href="http://www.reddit.com/r/programming/" target="_blank" title="programming reddit">programming reddit</a>. This week was an especially&nbsp; good one in terms of relevant content for me, with discussions on the <a href="http://www.reddit.com/r/programming/comments/7h3pa/perl_5_is_dying/" target="_blank">death of Perl 5</a>, <a href="http://www.reddit.com/r/programming/comments/7hcl0/perl_5_programmers_are_dying/" target="_blank">the difficulties of hiring Perl programmers</a> and <a href="http://www.reddit.com/r/programming/comments/7hl0l/photo_of_the_day_it_looks_like_youre_writing_a/" target="_blank">how stupid it is to write your own framework</a>. By strange coincidence, I just finished the alpha of a new in-house Perl 5 framework for my development team at work. And we're hiring!</p> <p>The two Perl articles were interesting because for three years I have worked with the language and up until earlier this year, I loathed it. This was mostly because of its awful support for Object Oriented Programming, but the fact that anyone I've worked with that called themselves a Perl programmer turned out to be a total amateur hack played a part too. After seeing no less than four guys come and go from our team this year after being 'found out' on their first big project, this quote from use.perl.org particularly resonated with me:</p> <blockquote> <p>We had no trouble <em>finding</em> Perl programmers. They were a dime a dozen. People write a couple of admin scripts in Perl and they put Perl on their CV. Now don't get me wrong, I have Java on my CV, but I would never <em>dream</em> of sitting down for a Java interview without their knowing up front that my knowledge is pre 1.5 and I don't know any of the modern tools. It's only there because I want employers to know that I have some exposure to it, not that I think I know it.</p> <p>Now, maybe I'm just being naive, but somehow people with Perl on their CV think they can do this job, but they can't. Not even close.</p> </blockquote> <p>My disdain for Perl and the quality of code that was being written was so great that I wrote a proposal for us to move our entire code base over to PHP. The scary thing is that the technical management accepted it, and I even got as far as completing an alpha PHP port of our (basic) in house framework before the whole project was abruptly cancelled by upper management for reasons unknown. When the suits put the kybosh on my PHP framework, I decided to <a href="http://www.dmclaughlin.com/2008/07/13/i-got-99-problems-but-a-manager-aint-one/" target="_blank">go covert and just start doing things right without them knowing</a>. What I've never really discussed is what, exactly, this involved.</p> <h3>Object Oriented Perl</h3> <p>The initial reaction was obviously to start looking for alternative work, but quitting a difficult situation isn't really in my make up. Plus, it's amazing what coming out of University and spending the next two years writing procedural Perl can do for your job prospects! So, with renewed determination, I sat down and asked myself - what is it that I can do with PHP that I can't do with Perl? The whole thing boiled down to the syntax of Classes - PHP and Java both had natural constructs for building your classes whereas in Perl it seemed like a nasty hack. Still, it was clear that moving from Perl wasn't an option and I wasn't going to let minute details stop me from writing good code any longer.</p> <p>The first thing I did was take Damien Conway's <a href="http://www.manning.com/conway/" target="_blank">book on Object Oriented Perl</a> and read it from cover to cover. What occurred to me whilst I was reading the introductory chapter on the basic concepts of Perl, was that this was the first time I had read anything at all about the language - every piece of code I had written in Perl previously was done using our in house framework which I had "learnt by doing." My experiences had always been at a very high level using a haphazard collection of Perl modules to do the very common tasks of web development - DB access, request details and parsing templates. Rather than truly understanding the underlying concepts of hashes, arrays, references, map, grep and regular expressions I just kinda lumped stuff together and hoped it work. Then I had the nerve to say the language was useless based on nothing more than the quality of the code I was writing.</p> <p>A few chapters into the book, which was actually a little out of date, I began to realise that Perl doesn't just offer everything that PHP does but, in the right hands, it's actually a really nice language. I wrote a few classes in Perl and decided that writing a new subroutine just to create a class wasn't worse or better than writing a Class and constructor in Java or PHP - it was just different. Within a few weeks of utilising my new found knowledge of Perl, I wasn't just writing code as clean as what I could write in PHP, but it was actually much more elegant.&nbsp; This was thanks to the way Perl handles named arguments to method calls and constructors - optional parameters were easy and my interfaces became self-documenting as a result.</p> <p>When I finished my first major OOP Perl project, it was something of a humbling experience - after two and a bit years of arrogantly proclaiming Perl to be a nothing language compared to PHP, the first real satisfaction I had felt after a job done came courtesy of language I spent so long trashing. This realisation that I really didn't know as much as I thought about programming led me to searching for "<a href="http://www.google.co.uk/search?q=PHP+sucks" target="_blank">PHP sucks</a>" and seeing that people had clued into that sentiment a lot sooner than I had; and with much better arguments than "the syntax for anonymous arrays sucks." After all my claims that PHP was the way forward, yeah, it was a pretty <a href="http://c2.com/cgi/wiki?HumbleProgrammer" target="_blank">humbling experience</a>.</p> <h3>Enter the Moose</h3> <p>Whenever I see a 'Perl guy' defend his language, the first thing they'll say is the <a href="http://www.cpan.org/" target="_blank">CPAN</a>. I had always known of it but had shied away from it for so long because, again, it didn't follow the same rules as my comfortable PHP shared hosting comfort zone. With me getting all philosophical over how wrong I was about Perl, I gave CPAN another shot and soon had modules like Template (aka <a href="http://template-toolkit.org/" target="_blank">Template Toolkit</a>) and <a href="http://search.cpan.org/~adie/Test-Class-0.31/lib/Test/Class.pm" target="_blank">Test::Class</a> up and running on our servers. I also started to look through the standard modules and was introduced to <a href="http://search.cpan.org/~rgarcia/perl-5.10.0/ext/Devel/DProf/DProf.pm" target="_blank">Devel::DProf</a> too - all of a sudden I had this language with an easy to use profiling and unit test ecosystem and an extremely powerful templating system. For the first time I felt like I was working in an environment that was the equal of the ones I read all those enthusiastic PHP, Python and Ruby developers blog about. And it had been there the whole time that I was complaining that Perl was out dated.</p> <p>The only remaining gripe I had with Perl was the Class definition syntax. I had gotten past the point where I blindly held the Java and PHP model for Classes as the Right Way, but every time I had to write my own "new" I couldn't help but feel like there was a better way. But never in a million years did I imagine something like <a href="http://www.iinteractive.com/moose/" target="_blank">Moose</a> existed.</p> <p>Moose isn't just an equaliser to the native OOP systems of the other big dynamic languages - it's the killer feature. People say that <a href="http://www.catalystframework.org/" target="_blank">Catalyst</a> is the Ruby on Rails or Django of Perl, but I disagree - Moose is the module bundle that makes Perl relevant again. There are plenty of modules on CPAN that try to make writing classes comparable to the way it's done in other languages, but the guys behind Moose had bigger ambitions and created something that provides features that no other language matches out of the box. If you had to install something like Moose just to get what other languages offer natively, then why not just use those other languages? That's why it's so important that Moose offers so much more.</p> <p>Getting into specifics is for future articles, so for now I'll leave you with a link to the <a href="http://search.cpan.org/~drolsky/Moose-0.62/lib/Moose/Cookbook.pod" target="_blank">Cookbook</a> and a sample of my Django-inspired CRUD model system for my new framework (courtesy of Moose sugar):</p> <pre class="sh_perl">package Feature;<br />use Snow::Model::Sugar;<br /><br />extends 'Snow::Model::Class';<br /><br />table 'features';<br />field 'feature_id' =&gt; (type =&gt; 'Int', primary_key =&gt; 1);<br />field 'title' =&gt; (type =&gt; 'Char', length =&gt; 255, required =&gt; 1);<br />field 'slug' =&gt; (type =&gt; 'Slug', from =&gt; 'title');<br />field 'reporter_id' =&gt; (type =&gt; 'Int', required =&gt; 1);<br />field 'assigned_to' =&gt; (type =&gt; 'Int');<br />field 'status' =&gt; (type =&gt; 'Enum', choices =&gt; ['open', 'development', 'complete']);<br />field 'posted' =&gt; (type =&gt; 'Datetime', auto_on_add =&gt; 1);<br />field 'description' =&gt; (type =&gt; 'Text', required =&gt; 1);<br /><br /># essentials<br />__PACKAGE__-&gt;meta-&gt;make_immutable;<br />1;</pre> <p>This code provides all the basic CRUD functionality with validation for each model defined. Of course this could have been done with the native has/isa functionality provided by Moose, but I liked this interface better and so did the guys who are going to be using this - the point is that Moose gave me the power to do this and so much more.</p> <h3>Life after PHP</h3> <p>I've read a few times that you learn more from a defeat than you do from a victory, and that certainly has been true in my case. I often think back and wonder what would have happened if the original attempts to "go PHP" had worked out. That project being cancelled has had such a dramatic effect on my approach, understanding and dedication to my profession. This blog, my recent promotion, learning Python and django, getting a VPS and learning more about the server stack - all stuff I wouldn't have dreamt of doing when knocking something up in PHP in a couple of days would have got the job done. I feel like I've learnt more in the last year than I have in the six that came before it.</p> <p>Could my post-PHP epiphany have come in Ruby or Python? Having played with Ruby and used Python (django) to rebuild my band website I can safely say that it could, but the point of this post is that it didn't come in those languages - it came in Perl. And after all the negativity lately I felt like it would be a good idea to share the positive experience I've had using Perl 5 and the great progress we're making at work to modernise our development practices without changing languages.</p> <h3>Perl going forward</h3> <p>What I've taken from all of this is that a language is only ever going to be what you make of it. Moving past my own anecdote: with projects like Moose, Catalyst and Mojolicious out there, there is no doubt that Perl is a powerful language that lets good developers write good code. So why is Perl dying? I agree with the general sentiment of both articles - Perl is losing ground to Python, PHP and Ruby and it IS getting harder and harder to find good Perl guys. What concerns me is the recommended actions for fighting the rut.</p> <p>The consensus in the Perl community seems to be that the areas of marketing, web design and their community organisation are where they are struggling, but these are all superficial next to the damage done by all the absolutely atrocious Perl code out there. I mean, surely the fact that PHP developers can sneer at the ugliness of most Perl code is a major warning sign?</p> <p>Rather than tart up use.perl.org with some gradients, what really needs to be done is for more examples of elegant, maintainable and tested code like the kind found on the <a href="http://mojolicious.org/" target="_blank">Mojo</a> project to be put out there for people to read and aspire to. Rails is a popular framework but that has very little to do with Ruby or the nice user interfaces on 37signals websites. Design is extremely important, but it starts at the code level. Get that right, then worry about the CSS.</p>Obama's maintenance nightmarehttp://www.dmclaughlin.com/2008/11/05/obama-maintenance-nightmare/<p><img src="../../../../ui/images/change.jpg" border="0" width="525" height="301" /></p> <p style="clear:both;">On the 1st of this month, my promotion at work became official and I am now an official "Software Architect." It follows three full years of advocating the upgrading and modernising of the way we write code on our "corporate" development team. In my <a href="../../../../2008/07/13/i-got-99-problems-but-a-manager-aint-one" target="_blank">first post in this blog</a> back in July, I wrote about how I was trying to save my career through a process called guerilla refactoring -- basically going rogue and fixing code and making it right without telling anyone. In the four months since that post, I became so confident that my work spoke for itself that I adopted a much simpler position - back me completely on the changes I want to make or I'm leaving.</p> <p>Thankfully, my employers chose to get on board the change train.</p> <p>For me I saw it as a personal victory. I don't like to quit something just because it's tough and my decision to stick it out and fight for change has been justified. Now I have to repay their faith by making the right changes and being patient through the long road ahead. I have enough experience in trying to implement small changes to know that trying to revamp the fundamentals of the way people work will be by far the most difficult thing I will ever embark on, but I wouldn't have demanded the promotion if I didn't believe I was man enough for the job.</p> <p>We have several hundreds of thousands of lines of legacy code, mostly procedural Perl, that powers all of our critical products which bring in millions of pounds a month. These systems started small but grew in complexity to become bloated and monolithic, bug-ridden products with severe dependencies that limited what could be done to improve them. But I believe I can change that and bring us into the 21st century. This means Object Oriented Programming. Code reviews. Unit Testing. Refactoring. Model View Controller and all manners of proven techniques for writing maintainable code.</p> <p>Over the next few months, I'll try to post regularly about the changes I attempt to make and the experiences of my most notable successes and failures. I'm sure there will be many of both.</p> <p>With all this talk of change, I'd just like to spare a thought as well to this American guy that I know who also won a promotion recently, although I doubt he had to fight as hard to get it as I did mine. Still, on the 20th of January 2009 Barack Obama will become the 44th President of the United States of America, and he's taking up probably the worst maintenance job in history. The last guy in charge made a complete mess of the existing system and it's going to be this guy's job to go in there and clean it up. Personally I wouldn't touch the job for love nor money, but he seems pretty confident that he can turn things around.</p> <p>And I wish him all the luck in the world.</p>The Django hype - it's not just its featureshttp://www.dmclaughlin.com/2008/11/05/the-django-hype-its-not-just-its-features/<p>I just finished relaunching my <a href="http://www.mesaverde.co.uk" target="_blank" title="Mesa verde">band website</a>. In the spirit of most of my personal projects recently, I have been determined to make a conscious effort to <a href="http://steve.yegge.googlepages.com/practicing-programming" target="_blank">practice programming</a>. To that end, my main goal was to use an MVC framework for the first time. As it turns out, I ended up going a lot further than that. Here is a list of the technologies or projects I've gained experience with through this pretty small project:</p> <ul> <li>Django Framework</li> <li>Python</li> <li>Blueprint CSS framework</li> <li>Setting up a server stack on a Virtual Private Server</li> <li>General UNIX systems administration</li> <li>nginx lightweight server platform</li> </ul> <p>All in, some good experience and a great advert for making a conscious effort to pick up new things. By far the most exciting 'new thing' for me was the <a href="http://www.djangoproject.com" target="_blank">Django Framework</a>, and most of the UNIX and server experience came as a result of needing to create a suitable deployment environment for the django applications I wrote.</p> <p>Now, I have attempted to use many of other MVC frameworks (Zend Framework, CakePHP, Catalyst and Ruby on Rails to be precise) before I tried django but ultimately found them an overly complicated or frustrating experience. Why then did django hook me in to the point where I went from a cheap shared hosting solution to a fresh Ubuntu install costing more than double in monthly costs?</p> <p>Well, there's the obvious killer feature - the automatic admin module. You really have to see this in action to find out how unbelievable it is - from the automatic validation on the forms to the slick JavaScript interfaces for handling Many to Many relationships. They really thought of everything. The model and ORM system is fantastic too, as is template inheritance and the comment/RSS frameworks. All of these features (and more) are fantastic, but in my opinion the widespread adoption of django owes a lot to two of the other killer features of django - the documentation and the development server.</p> <h3><strong>Documentation</strong></h3> <p>Having to write documentation is the worst part of creating reusable modules of code that you want other people to use, but it's also one of the most important parts when it comes to adopting a framework. When I tried to do a small project in Ruby on Rails, I went ahead and downloaded all the bits I needed from links on the official site. Then when I went to the "quick start" tutorials from that same site, they were all for RoR 1.3 rather than the backwards incompatible 2.0 release I had downloaded from the site. I eventually found a tutorial for 2.0 on a <a href="http://www.akitaonrails.com/2007/12/12/rolling-with-rails-2-0-the-first-full-tutorial" target="_blank">brazilian website</a> that helped me create my small app but the whole experience was extremely disappointing.</p> <p>With Zend Framework 1.5, the situation was the same - the documentation was there but the sheer wealth of it was overwhelming. There was documentation for each compoment in the framework and constant stressing that everything was decoupled if you needed it to be - but no quick tutorial on what to do if you just wanted to use the framework as a whole to see what it offered. In their defence, as of 1.6 this has now been fixed and a quick start link on the framework homepage now links to a quick start tutorial.</p> <p>Django's documentation, by contrast, is by far the best I've ever used. Not only has the framework had the (regularly updated) standard documentation to supplement the pre 1.0 releases, but you also have the <a href="http://www.djangobook.com/" target="_blank">free django book</a> if that's how you like to do your learning. With the wealth of features django offers, it would be extremely easy for the documentation to become bloated and overwhelming, but the <a href="http://docs.djangoproject.com/en/dev/" target="_blank">reality</a> is that it does a great job of presenting the information you need, when you need it. The examples they use to show off features in the documentation almost double up as an FAQ, every time I wanted to do something a bit different I typed django and the feature name into a google and a page from this documentation came up as a result. As an absolute beginner, the introductory tutorial is right there with plenty of supplementary information about related technologies and anticipated problems, and it takes you through the basics gradually - introducing complex parts only when there is a good reason.</p> <p>Everyone involved in writing and editing this information should pat themselves on the back, it has been superbly well written and organised and sets a new benchmark that puts the competition to shame.</p> <h3><strong>Development Server</strong></h3> <p>The built-in development server was by far the most useful feature in getting me on board using django. Even when I tried to set up a "mock live" environment on my Windows Vista machine after doing the brunt of my "learning" on the development server, I had great difficulties with environmental paths and the general leap in difficulty deploying django over Apache compared to one-click installer PHP development solutions like xampp and Wampserver. And this is after I was sold on the framework!</p> <p>Whoever came up with the idea of this development server, clearly understood that when you download a framework <strong>you just want to learn the framework,</strong> not how to set up a server stack that lets you run python web applications. The latter should become a problem only once you're sold on the framework and have created something you want to deploy. For Windows users with zero to limited UNIX experience, this really will reel in a whole bunch of people who would have otherwise had to wait until Wampserver for django came along.</p> <h3><strong>Conclusion</strong></h3> <p>The Django Project is a fantastic example of how the little things in your project can make all the difference. It would have been so easy for the team to just target open source enthusiasts who are already extremely familiar with UNIX and for whom setting up a django server platform would have been pretty straight forward, but putting the development server right in there completely eliminates the major barrier to entry for a whole other demographic of native Windows/shared hosting users.</p> <p>Likewise, the documentation for django is ridiculously good. For such a young project (that only recently hit 1.0) it would also have been so easy for them to neglect the mundane part of writing about an ever-evolving code base and just concentrate on getting things right on that side of things. But the documentation from the very early versions has always been great and it paid off big.</p> <p>When you see the effort they've put in to getting the details right, you can only imagine the quality of the code underneath.</p>Complete guide to deploying django on Ubuntu with nginx, FastCGI and MySQLhttp://www.dmclaughlin.com/2008/11/03/complete-guide-to-deploying-django-on-ubuntu-with-nginx-fastcgi-and-mysql/<p>I recently deployed my first django project and it was an eye-opening experience to say the least. Coming from Windows, PHP, Wampserver and the cPanel shared hosting culture, starting with a fresh Ubuntu install and having to build the stack myself was something of a culture shock. There were of course a wealth of tutorials out there to help me get it up and running, but the reason I'm writing this is because the information I needed to get from brand new VPS to fully functional django app was split across many different tutorials, some of which were better than others. For my own reference (and for when I inevitably break something and need to start from scratch!), here is how I did it in ten simple steps:</p> <h3>Step 1: Get a slice</h3> <p>It's important to realise that you don't actually have to abandon the shared hosting model to deploy your django application, many shared hosts specialise in django hosting since the work needed to do this yourself can be quite intimidating. <a href="http://stackoverflow.com/questions/2729/what-hosting-service-is-best-for-django-applications" target="_blank">This thread </a>over at Stack Overflow has a good outline of the available options.</p> <p>I chose the route of getting a VPS (Virtual Private Server) because I liked the idea of having total control over the platforms my hosting service provided as well as the desire to get some systems administration experience under my belt. It's hard to get the chance to play with this stuff in a commercial environment when you have live systems with millions of users relying on everything working. So with that in mind, I started looking for a good VPS provider and after overwhelming recommendation, quickly settled on <a href="https://manage.slicehost.com/customers/new?referrer=80c0f3c436840408953c01f60fb02a83" target="_blank">slicehost</a>. Since my django project wouldn't be too high-traffic, I chose the 256MB slice with the default Linux distribution of Ubuntu 8.04.1 (Hardy).</p> <h3>Step 2: SSH into the slice</h3> <p><a href="http://articles.slicehost.com/2007/9/6/logging-in-via-putty" target="_blank">Windows users use this guide if you're having problems</a>.</p> <h3>Step 3: Set up a non-root user account</h3> <p>I can't stress enough that you follow the <a href="http://http//articles.slicehost.com/2008/4/25/ubuntu-hardy-setup-page-1" target="_blank">two</a> <a href="http://articles.slicehost.com/2008/4/25/ubuntu-hardy-setup-page-2" target="_blank">guides</a> on slicehost for best practices for setting up your slice. The most important part is that you <strong>do not do anything under the root account</strong>. I put that in bold because in my haste I ignored all the stuff about creating a seperate user account for myself as I planned to be the only person logging into the server. This is fine, but when you create files and directories with root the default permissions are extremely strict and that will cause major problems when your server tries to read and/or execute these files later.</p> <h3>Step 4: Install the stack</h3> <p>You may have heard of the term LAMP before - it usually refers to the common server stack consisting of Linux, Apache, MySQL and PHP.&nbsp; Since we're starting with a nice fresh slice, we're going to have to set this up ourselves (with Python and Django replacing PHP, of course).</p> <p>The only notable thing here is that I've went with nginx over Apache. This is because on a 256MB slice, I want to make the most of my limited RAM. The two major alternatives to Apache in the lightweight category are lighttpd and nginx. After doing a bit of research, I installed both, played with the virtual hosts and config and decided I liked nginx better. <a href="http://hostingfu.com/article/nginx-vs-lighttpd-for-a-small-vps" target="_blank">This article</a> and others like it provide a good overview of all the options.</p> <p><strong>The stack:</strong></p> <p>Linux distro - Ubuntu 8.04.1<br /> Server - nginx 0.5.33<br /> Database - MySQL 5.0.51<br /> Language - Python 2.5.2 (default with Ubuntu)</p> <h4><strong>Step 4a: Installing nginx</strong></h4> <p>Getting nginx up and running to serve static files is quite straight forward, and the guides on slicehost articles were extremely easy to follow so I'm not going to repeat them here:</p> <ol> <li><a href="http://articles.slicehost.com/2008/5/13/ubuntu-hardy-installing-nginx-via-aptitude" target="_blank">Install nginx with aptitude</a></li> <li><a href="http://articles.slicehost.com/2008/5/15/ubuntu-hardy-nginx-configuration" target="_blank">Basic configuration of nginx</a></li> <li><a href="http://articles.slicehost.com/2008/5/16/ubuntu-hardy-nginx-virtual-hosts" target="_blank">Create a virtual host for your django site</a></li> </ol> <p>By this point you should have at least the default nginx page displaying under your slice IP address. Getting a domain set up on your slice is quite tricky too but luckily there's <a href="http://articles.slicehost.com/2007/10/24/creating-dns-records" target="_blank">an easy guide</a> for that as well.</p> <p><strong>Step 4b: Installing MySQL</strong></p> <p>Again, aptitude makes this easy. Run the following command:</p> <pre class="sh_sh">sudo apt-get install mysql-server mysql-client</pre> <p>You will be taken through a wizard to create a root account, make sure you do this then test the install by entering the mysql command line client:</p> <pre class="sh_sh">mysql -u root -p</pre> <p>Just being prompted for your password tells you that MySQL was installed successfully. You should go ahead and create a database for your django app to use later. I recommend at some point you <a href="http://articles.slicehost.com/2008/7/10/mysql-creating-and-editing-users" target="_blank">create a user with restricted permissions</a> for your web client to connect as.</p> <p><strong>Step 4c: Confirm Python install<br /> </strong></p> <p>Ubuntu comes with Python pre-installed, you can type 'python' into the shell to make sure.</p> <h3>Step 5: Install django</h3> <p>Install django from the latest development branch. We will need to install subversion first:</p> <pre class="sh_sh">sudo aptitude install subversion<br />mkdir /home/username/installers<br />cd /home/username/installers<br />sudo svn co http://code.djangoproject.com/svn/django/trunk/<br />sudo python trunk/setup.py install</pre> <p>This should be straight forward. We install subversion, check out the code somewhere (I recommended checking out installers and projects to one location to keep your slice organised) and then run the set up script. You should get clear feedback from the prompt to let you know how everything went.</p> <h3>Step 6: Install django dependencies</h3> <p>Our goal is to run django under FastCGI with a MySQL database. If you go ahead and try to do this, you'll be told there are missing packages when you run syncdb and later when you try to run django as a FastCGI:&nbsp; we need to install both flup and python-mysqldb.</p> <p>Installing python-mysqldb is easy:</p> <pre class="sh_sh">sudo apt-get install python-mysqldb</pre> <p>To install flup we first need to install "easy_install" - a Python utility for installing packages. Here are the commands:</p> <pre class="sh_sh">cd /home/username/installers<br />sudo wget http://pypi.python.org/packages/2.5/s/setuptools/setuptools-0.6c9-py2.5.egg<br />sudo sh setuptools-0.6c9-py2.5.egg<br />sudo wget http://www.saddi.com/software/flup/dist/flup-0.5-py2.5.egg<br />sudo easy_install flup-0.5-py2.5.egg</pre> <p>Once again, pay attention to the feedback at the command prompt to make sure everything is (hopefully) installing successfully.</p> <h3>Step 7: Create a test project</h3> <p>Create a directory somewhere on your file system and start a django project with a small default app, then go in and change the settings to look for your MySQL database (you will need to create a new database for django to use if you haven't already done so). If you used the slicehost method of organising your code, you would run commands like this:</p> <pre class="sh_sh">cd /home/username/public_html/mydomain.com/private/<br />django-admin.py startproject myproject<br />cd myproject<br />python manage.py startapp myapp<br />nano settings.py</pre> <p>You then need to enter your database details and paths. Here is a sample for a MySQL connection:</p> <pre class="sh_sh">DATABASE_ENGINE = 'mysql'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #<br />DATABASE_NAME = 'mysite'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #<br />DATABASE_USER = 'websites'&nbsp;&nbsp;&nbsp;&nbsp; #<br />DATABASE_PASSWORD = 'mypasswd' #<br />DATABASE_HOST = ''&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #<br />DATABASE_PORT = ''&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #</pre> <p>Don't worry too much about the other path details (like media and templates) for now, all we're doing here is trying to get that default "welcome to django" page to display so that we can confirm everything else is working.</p> <h3>Step 8: Set up nginx conf for django</h3> <p>When you installed nginx, hopefully you took the trouble to get yourdomain.com running and displaying static content on your nginx install - because we're about to edit the config file to make it serve django content. If you didn't, then follow these steps:</p> <ol> <li>Change your domains nameserver records to the slicehost settings. Whoever you registered your domain with will provide the tools to do this. See your slicehost manager control panel for the nameserver domains to point to.</li> <li><a href="http://articles.slicehost.com/2007/10/24/creating-dns-records" target="_blank">Use the DNS wizard in slicehost manager to handle the domain</a></li> <li><a href="http://articles.slicehost.com/2008/5/16/ubuntu-hardy-nginx-virtual-hosts" target="_blank">Set up a nginx virtual host which will handle requests to this domain</a></li> </ol> <p>If you don't have a domain yet and just want to use the IP for the time being, use the default config file located at (<code>/etc/nginx/sites-available/default</code>) in the following examples.</p> <p>Open your domain config file:</p> <pre class="sh_sh">sudo nano /etc/nginx/sites-available/mydomain.com</pre> <p>And change it to look like this, substituting in your project path:</p> <pre class="sh_sh">server { listen 80; server_name www.yourdomain.com; access_log /path/to/yoursite.com/log/access.log; error_log /path/to/yoursite.com/log/error.log; root /path/to/yoursite.com/public; location /site_media { root /path/to/yoursite.com/public; } location / { # host and port to fastcgi server fastcgi_pass 127.0.0.1:8081; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param QUERY_STRING $query_string; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_pass_header Authorization; fastcgi_intercept_errors off; } }</pre> <p>This will direct all web requests to http://www.yoursite.com/ to a FastCGI process (i.e django) <em>except </em>those under http://www.yoursite.com/site_media/. The port you use here has to be different for each instance of django you want to run, so take a note of it here as we'll need it when we run the FastCGI process later.</p> <p>I had a number of legacy links on my band website that I had to transfer over and I also used a slightly different directory structure from the slicehost articles but it all follows the same pattern. For reference, here are my settings:</p> <pre class="sh_sh">server { # redirect all mesaverde.co.uk requests to www.mesaverde.co.uk listen 80; server_name mesaverde.co.uk; rewrite ^/(.*) http://www.mesaverde.co.uk/$1 permanent; } server { listen 80; server_name www.mesaverde.co.uk; access_log /home/david/websites/mesaverde.co.uk/log/access.log; error_log /home/david/websites/mesaverde.co.uk/log/error.log; root /home/david/websites/mesaverde.co.uk/public; location /ui { root /home/david/websites/mesaverde.co.uk/public; } location /mp3 { root /home/david/websites/mesaverde.co.uk/public; } location ~* ^.+\.(jpg|css|jpeg|gif|png|ico|zip|pdf|txt|wav|js|mov|mp3) { access_log off; expires 30d; } location / { # host and port to fastcgi server fastcgi_pass 127.0.0.1:8081; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param QUERY_STRING $query_string; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_pass_header Authorization; fastcgi_intercept_errors off; } } </pre> <p>All my CSS, JavaScript and image files are located inside www.mesaverde.co.uk/ui/ and I also have a page of mp3s that I host at http://www.mesaverde.co.uk/mp3/, using this set up I don't involve django in any static file serving.</p> <h3>Step 9: Run django as a FastCGI</h3> <p>The final step is starting up django as a FastCGI. Remember in the development mode when you had to use runserver to test your code? Well it's the same idea here, with a couple of extra options:</p> <pre class="sh_sh">cd /path/to/your/project<br />python manage.py runfcgi host=127.0.0.1 port=8081 --settings=settings</pre> <p>Note that the port you specify here should match the one you chose in your site conf in step 8. Once you have run this command, you can go to http://www.yourdomain.com and if all is well, you will get the default 'welcome to django' page.&nbsp; Congratulations, you have deployed django and the worst is over!</p> <h3>Step 10: Settings, uploading projects and other configuration</h3> <p><strong>Setting up an FTP server</strong></p> <p>Now that django is working, you'll probably want to upload your django app and attempt to get that working. If you come from a shared hosting background like I did, you'll probably take FTP access for granted. Unfortunately it doesn't quite work like that. You'll need to install an FTP server on your slice, but this is a lot easier than it sounds. I chose VSFTP for this:</p> <pre class="sh_sh">sudo aptitude install vsftpd</pre> <p>Once it's installed (and automatically started) you'll now need to open up the conf and change a couple of key settings:</p> <pre class="sh_sh">sudo nano /etc/vsftpd.conf</pre> <p>Most importantly, you should disable anonymous access and set up access for local users:</p> <pre class="sh_sh">anonymous_enable=NO<br />local_enable=YES<br />local_umask=022</pre> <p>The two local settings allow you to FTP in as the same user you SSH in as and make sure that the permissions are reasonable. Once you change these settings, restart your FTP server for them to take effect:</p> <pre class="sh_sh">sudo /etc/init.d/vsftpd restart</pre> <p>Now you can log into your slice with your usual FTP client and upload your django project files. Use your slice IP, and the username and password you've been using to SSH to your slice. Remember to change settings.py to reflect the new templates path.</p> <p><strong>Admin Media<br /> </strong></p> <p>If your project is using the automatic admin then you might notice it looks a bit bare. That's because django doesn't automatically load the media for you like it does on the development server. We'll need to set this up.</p> <p>The admin media is located in a restricted part of your system that you need superuser permissions to access. So first we grant it more liberal permissions:</p> <pre class="sh_sh">sudo chmod +rx /usr/lib/python2.5/site-packages/django/contrib/admin/media</pre> <p>Here we've given it read and executable permissions for all users. Next we need to make this directory available inside the directory we chose for our static files when we set up our nginx conf (your site_media directory or whatever you named it). The typical Windows way to do this is just to make a copy, but in UNIX we can use a <a href="http://en.wikipedia.org/wiki/Symbolic_link" target="_blank">symbolic link</a> to achieve this.</p> <pre class="sh_sh">ln -s /usr/lib/python2.5/site-packages/django/contrib/admin/media /home/username/public_html/yoursite.com/public/site_media/admin</pre> <p>The idea is that you can now access these files through a URL like www.yoursite.com/site_media/admin/dashboard.css. By default, admin media is served through www.yoursite.com/media/ so we need to change the ADMIN_MEDIA_PREFIX setting in settings.py:</p> <pre class="sh_sh">ADMIN_MEDIA_PREFIX = '/site_media/admin/'</pre> <p>Restart django and the admin should now look more familiar.</p> <p><strong>Restarting Django</strong></p> <p>When we make changes to nginx, there is a handy init script that takes care of it for us:</p> <pre class="sh_sh">/etc/init.d/nginx restart</pre> <p>So <a href="http://docs.djangoproject.com/en/dev/howto/deployment/fastcgi/" target="_blank">using information from the official docs</a> let's create a similar one for django. Create the script in your /usr/local/bin directory.</p> <pre class="sh_sh">sudo nano /usr/local/bin/yoursite-restart</pre> <p>Then save into this file the following script:</p> <pre class="sh_sh">#!/bin/bash PROJDIR="/home/username/public_html/yoursite.com/private/project"<br />PIDFILE="$PROJDIR/yoursite.pid" cd $PROJDIR<br />if [ -f $PIDFILE ]; then<br />&nbsp;&nbsp; kill `cat -- $PIDFILE`<br />&nbsp;&nbsp; rm -f -- $PIDFILE<br />fi exec python ./manage.py runfcgi host=127.0.0.1 port=8081 pidfile=$PIDFILE --settings=settings</pre> <p>Obviously you need to change the path to point to your project directory and make sure the port setting matches the one in your nginx config. Save the file, give it executable permissions and then make sure django isn't currently running:</p> <pre class="sh_sh">sudo chmod +rx /usr/local/bin/yoursite-restart<br />ps -ef | grep "fcgi"</pre> <p>This will give an output of currently running processes which contain "fcgi" in them. It should look like:</p> <pre class="sh_sh">root&nbsp;&nbsp;&nbsp;&nbsp; 12085&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; 0 Nov02 ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00:00:00 python ./manage.py runfcgi host=127.0.0.1 port=8081 --settings=settings<br />root&nbsp;&nbsp;&nbsp;&nbsp; 12086 12085&nbsp; 0 Nov02 ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00:00:02 python ./manage.py runfcgi host=127.0.0.1 port=8081 --settings=settings<br />root&nbsp;&nbsp;&nbsp;&nbsp; 12087 12085&nbsp; 0 Nov02 ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00:00:02 python ./manage.py runfcgi host=127.0.0.1 port=8081 --settings=settings<br />root&nbsp;&nbsp;&nbsp;&nbsp; 14818 12085&nbsp; 0 10:29 ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00:00:00 python ./manage.py runfcgi host=127.0.0.1 port=8081 --settings=settings<br />root&nbsp;&nbsp;&nbsp;&nbsp; 14869 12085&nbsp; 0 12:23 ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00:00:00 python ./manage.py runfcgi host=127.0.0.1 port=8081 --settings=settings<br />root&nbsp;&nbsp;&nbsp;&nbsp; 16544 12085&nbsp; 0 15:54 ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00:00:00 python ./manage.py runfcgi host=127.0.0.1 port=8081 --settings=settings</pre> <p>The key process we're interested in is the first in this list. We want to take note of the first number - 12085. This is the process ID. The other runfcgi processes are just children of this process and killing the parent will kill the children processes too:</p> <pre class="sh_sh">kill 12085</pre> <p>Django is now stopped. We can test the bash script we just created by running:</p> <pre class="sh_sh">sudo yoursite-restart</pre> <p>If you created the file in /usr/local/bin you don't need to specify the full path to the file, which is why we can just type the script name directly. Django should now be running again and each time you make changes to your django settings or models, etc. you can just run this command to restart the django processes.</p> <p>Congratulations, you're done!</p> <h3>Conclusion</h3> <p>Although there are a lot of small steps, deploying django is simple and a good exercise in beginning to understand the most popular software stack that supports the web. For Windows user in particular, this kind of basic systems administration will be a good introductory exercise to UNIX and set you apart from many applications developers who avoid this kind of thing.</p>I Got 99 Problems But a Manager Ain't Onehttp://www.dmclaughlin.com/2008/07/13/i-got-99-problems-but-a-manager-aint-one/<p>There's a few predictable ways people deal with unhappiness in life. They can dwell on it and make everyone around them miserable. They can suck it up and say "that's life." Or they can actually do something about it.</p> <p>Me? I tend to go through a cycle of all three. One thing I realised from going on a few job interviews and looking at my list of complaints about my current work environment was that the problems I had were a veritable checklist of every working environment out there. Legacy code? Which established software company doesn't have that? A standard set of tools and practices for common problems? I'd hope so! Changing something that isn't broke?</p> <p>There's nothing worse than reinventing the wheel for no reason.</p> <p>Except when you're being asked to make major changes to a bunch of spaghetti procedural code full of inconsistent architectural decisions and quick-fix hacks for the numerous bugs that appeared since launch. Oh and could you improve performance whilst you're at it? And by the way we're already behind schedule. No manager wants to hear "complete rewrite" when they're adding something that took the guy before you two or three weeks to hack in there.</p> <p>So I hacked it in just that one time. And the next. And again. And in no time at all that horrible legacy code I used to blame on the other guy is now 50% mine. Oops! And those archaic practices and standards now dominate my CV .</p> <p>Not my managers CV. Or their managers CV.<em> My</em> CV.</p> <p>To top it all off, there has been a steady rise in web development jobs looking for expert OOP programmers and experience with MVC frameworks. It's all Zend Framework this, Rails that and Django another thing. In my office we use Perl. And not even cool Perl like Catalyst or Template::Toolkit. We're talking HTML::Template Perl here. I'm not even relevant in modern Perl jobs (all 2 openings per year).</p> <h2>Guerilla Refactoring</h2> <p><strong>Guerilla Refactoring</strong> is a phrase I thought I had coined but was in fact <a href="http://codebetter.com/blogs/kyle.baley/archive/2007/12/13/guerrilla-refactoring-or-quot-how-to-bring-down-a-totalitarian-regime-quot.aspx" target="_blank">soundly beaten</a>. Essentially it's the act of covertly fighting the good fight agains the almighty resistance of middle management, developing your own skills and getting better at your profession while you're at it.</p> <p>See, the biggest problem I had six months ago was that even if I could start from scratch and do a total rewrite of the code I was having to maintain, I didn't have the real world experience to put all the theory into practice. Sure I knew what the acronyms MVC and <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself" target="_blank">DRY</a> meant, but it's not until you start trying to write truly reusable code that <a href="http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It" target="_blank">YAGNI</a> and <a href="http://en.wikipedia.org/wiki/KISS_principle" target="_blank">KISS</a> suddenly become the acronyms of choice. The code behind a good API and simple interface can often be extremely complex, and it takes a lot of experience to get it right.</p> <p>Things changed for me during the last major project I worked on. The existing codebase was so huge that no business case in the world could justify a complete rewrite of the existing code to achieve the stated goals of the project, on that issue I had admitted defeat. So there I was, hacking away on a OOP/Procedural mash-up with some hundreds of thousands of lines of legacy code when I found myself about a week ahead of the schedule with some time to burn. What I did next was something I did for the first time in my professional career - rather than alert my manager to my heroic ability to beat the schedule, I went back and improved the design of a piece of fully functional and tested code I had written. I believe they call it refactoring?</p> <p>It was hardly a pioneering moment, refactoring is a fundamental concept to agile methodologies and OOP programming books across the land. But I work in an Enterprise environment and when a manager asks me what I've done and I show them a fully-functional solution, unfortunately their first thought isn't "that's great but I wonder if david could improve the code and incorporate some advanced techniques so he can outgrow us and get a better job". In an enterprise environment, to improve the maintainability or scalability of a piece of working code you generally have a fight on your hands. If they know you're doing it, anyway.</p> <p>The refactoring I did was extremely successful, I turned 300 lines of procedural code into a completely reusable class. When the same problem inevitably came up a few days later at another part of the application, I trimmed yet more time off the schedule by plugging my class in there. The actual process of reusing the code raised some flaws in the initial design as well as some areas that needed improvement, so I went ahead and used the time saved to make those to my class. Coding at work actually started getting interesting again.</p> <p>Soon I had the Guerilla Refactoring process down to an artform. I would solve whatever problem I was facing as fast as possible, then I would spend the rest of the budgeted time refactoring the design of my code and any surrounding code. My refactorings were subtle and isolated and I burnt my fingers on some misapplication of a lot of theory without having to commit to any major architectural decisions. Once a lot of those rookie mistakes were out of my system, I was having to do less and less refactoring because I was getting it right sooner. I became so confident in the long-term benefits of Guerilla Refactoring that it became less "guerilla" and more "public displays of affection for".</p> <h3>We can't all work for Google</h3> <p>If you're lucky enough to be working in some small, dynamic and modern web development team with great seed engineers and all the latest and greatest agile practices then you probably scoff at the idea of having to go behind your managers back to do things right. But it's the reality for most people working in the Enterprise environment.</p> <p>Guerilla Refactoring works because you don't break budget or blow a deadline by trying to rewrite an entire application when you were asked to solve a simple problem. Nor do you become responsible for an overblown and complex mess of an OOP architecture when you're still wet behind the ears. You simply work within the time you're allowed and <a href="http://www.codinghorror.com/blog/archives/001134.html" target="_blank">go dark</a> for a period of that time.</p> <p>If the situation I was in is anything like yours, give it a try. It might just save your sanity. And your career.</p>