Programming Like It’s 1999

This article was published yesterday. It shows a way to extract data about a film from IMDB and put it into a local database. Actually, it doesn’t even do that. It produces SQL that you can then run to insert the data.

It’s all rather nasty stuff and indicative of the fact that most people using Perl are still using idioms that would have made us shudder ten years ago.

There were a few things that I didn’t like about the code. The use of curl to grab data from the web site, the indirect object syntax when creating the XML::Simple object and, in particular, the huge amount of repetitive code used to create the SQL statements.

So I did what anyone would do in my situation. I rewrote it. Here’s my version.

I haven’t actually changed that much. I’ve tidied up a bit. Switched to using LWP::Simple, removed some unnecessary escaping, things like that. I have made two pretty big changes. I’ve got rid of all of the nasty variables containing data about a film. A film is a single object and therefore should be stored in a single variable. And, happily enough, the $data you get back from XMLin contains a hash that does the trick perfectly.

The second change I made was to rejig the way that the SQL is created. By using an array that contains the names of all of the columns in the table, I can generate the SQL programmatically without all of that repetitive code. I’ve even made the SQL a little safer by explicitly listing the columns that we are inserting data into (this has the side effect of no longer needing to insert a NULL into the id column).

Of course, this would just be a first step. The whole idea of generating SQL to run against the database is ugly. You’d really want to use DBIx::Class (or, at the very least, DBI) to insert the data directly into the database. And why mess around with raw XML when you can us something like IMDB::Film to do it?

At that point in my thought process I had an epiphany. You don’t need the database at all. The IMDB data changes all the time. Why take a local copy? Why not just use the web service directly with IMDB::Film (or perhaps WebService::IMDB – I haven’t used either of them so I have no strong opinions on this).

In general, I think that the original code was too complicated. Which made it hard to maintain. My version is better (but I am, of course, biased) but it can be made even better by using more from CPAN.

CPAN is Perl’s killer app. If you’re not using CPAN then you’re not using half the power of Perl.

What do you think? How would you write this program?

Update: A few people have mentioned the fact that I’m directly interpolating random data into my SQL statements – which is generally seen as a bad thing as it opens the door to SQL injection attacks. In my defence, I’d like to make a couple of points.

Firstly, the data I’m using isn’t just any old data. It’s data that is returned from the IMDB API. So it would be hard to use this for a malicious attack on the system (at least until Hollywood makes a film about the life of Bobby Tables).

Secondly, I am cleaning the data before using it. I’m escaping any single quotes in the input data. I think that removes the possibility of attack. I could be wrong though, if that’s the case, please let me know what I’m missing.

But, in general, I agree that this approach is dangerous. This is one of the major advantages of using DBI. By using bound parameters in your SQL statements you can remove possibility of SQL injection attacks.

Update 2: You can, of course, rely on Zefram to point out the issues here. His comment is well worth reading.

Other people (on IRC) raised the potential of other Unicode characters that databases treat as quote characters but that aren’t covered by my substitution.

Update 3: Here’s a local copy of the original code.

Send to Kindle

Too Easy or Too Hard

We hear a lot of people complaining that programming in Perl is too difficult, but I think that a lot of these problems stem from people making the opposite assumption – that writing Perl is easier than it actually is. Let me share a couple of examples. I’ve lightly disguised the companies in question – so if you think you recognise a place where we’ve worked together you’re probably wrong.

In the first, I’m working for a global organisation. Most of their bespoke software is written in Java, but (like pretty much every company) there are a few Perl programs running vital parts of the infrastructure. This company have also outsourced a lot of their maintenance work to another company in India. This Indian company has dozens of people who are dedicated to working on my client’s systems. But they are Java programmers and every once in while they need to do some work on a Perl program.

This company has an internal IRC network and there’s a Perl channel which I keep half an eye on whilst getting on with my work (which is maintaining a huge Perl program). A few times a day one of these Java programmers turns up on the Perl channel explaining a problem they have to solve in a Perl program and asking for help. In pretty much every case, the problem boils down to the Java programmer having major misconceptions about how Perl works. Perl programmers on the channel try their hardest to to help, but it’s often a frustrating experience. Usually the correct answer is “go away and read Learning Perl and Intermediate Perl, then you will understand how the code works”. But these programmers don’t have the time to do that. They need this task finished in an hour. Often it’s a task that could be easily achieved in an hour – but only after you’ve done the groundwork of understanding how Perl works.

The problem this company had was that Perl wasn’t seen as being as important as it actually was. People in the Indian company saw it as a “scripting language” that any of their (no doubt highly qualified) Java programmers would be able to use without any preparation or training. That’s clearly not the case.

But, I hear you say, that’s not fair. Perl and Java are really different languages. I’m glad you pointed that out as it’s a nice link to my second example.

In this example, I’m working for a dotcom company London. Like so many dotcom companies they have a Perl codebase that was thrown together five years ago in a couple of months by people who didn’t really know what they were doing. This company has the added problem that they are finding it hard to recruit people with Perl experience. So they start recruiting people with experience of languages like Python and Ruby in the belief that these languages are so similar that the programming skills are completely interchangeable.

And, of course, Perl, Ruby and Python are all a lot closer to each other than they are to languages like Java. But there are differences. Important differences that aren’t just syntactic. I can read Python and Ruby just fine. But if I got a job where I had to write a lot of either of those languages, I wouldn’t assume that I could just pick it up by osmosis, I’d get a book and read about the language. If I was going permanent at the company, I might even suggest that they send me on a training course.

Conversations with these non-Perl programmers often took a predictable course. They’d start complaining that the code was hard to read. This was hard to counter as a lot of the code was horrible. But if you pointed out some of the newer and better code, they wouldn’t see the improvement. They would insist that somehow Ruby or Python code was inherently easier to read than Perl code. I’d try to point out that Perl programmers find Perl code as easy to read as Python (or Ruby) programmers find Python (or Ruby).

So there seems to be this perception that Perl should be as easy to read as Random Programmer’s favourite language. And I don’t understand why that is. Just because I’ve been programming for almost thirty years, I don’t expect to be able to program in any language I happen to look at – well, certainly not well enough to be paid for doing it.

I’m not sure what we can do to counter this misconception. I think it probably stems from the late 90s when everyone was writing Perl. And if everyone is doing something, then it must be really easy.Of course, most people were writing really horrible Perl because Perl isn’t as easy as they thought it was.

Not sure it’s possible to sum this up in a simple marketing slogan. “Perl is Easy (but not as easy as you think)”.

Send to Kindle

Crufty Old Perl

It’s eighteen months since I wrote “Why Corporates Hate Perl” and it’s worth pointing out that the company I discussed in that article which was dropping Perl in favour of PHP and Java is still employing as many good Perl programmers as it can find.

I talked in that article about some rather unsubtle social engineering that had been going on at that company. Management had started to talk about Perl as a “legacy language” in an attempt to persuade the business that they really don’t want their applications written in Perl. That doesn’t seem to have been as successful as I feared it would be.

But there’s another kind of social engineering that I’ve seen going on. And this is happening at the developer level. I’ve lost count of the number of times I’ve been sitting in meetings with developers, discussing ways to improve the quality of crufty old Perl code when someone throws in the (more than half-serious) suggestion that we should just rewrite the whole thing using Rails or Django.

There seems to be this idea that switching to a new framework in a new language will act as some time of magic bullet and that suddenly all of our problems will be solved. There are so many ways that this perception is flawed, Here are my two favourites.

  1. The current system is old and crufty not because it’s written in Perl, but because it was written by people who didn’t understand the business requirements fully, didn’t know their tools particularly well or were under pressure to deliver on a timescale that didn’t give them time to design the system properly. Often it’s a combination of all three. Given the time to rewrite the system from scratch, of course it will be better. But it will be better because the business is better understood and tools and techniques have been improved – not because it’s no longer written in Perl.
  2. Frameworks in other languages are not easier to use or more powerful than frameworks in Perl. Anything that you can do with Rails or Django you can do just as easily with Catalyst. It’s using a framework that’s the big win here, not the particular framework that you use. Sure, if you’re a Ruby house then using a Ruby framework will probably match your existing developers’ skills more closely but if your current system is written in Perl then, hopefully, you have a team of people with Perl skills and that’s going to be the language you’ll want to look at.

I’m tired of Perl being seen as a second-class citizen in the dynamic languages world. I freely admit that there’s a lot of bad Perl code out there (I’ll even admit to writing some of it) but it’s not bad Perl code because it’s Perl, it’s bad Perl code because it’s bad code.

This is what the Perl marketing initiative is for. We need people to know that Perl is not the same language that they stopped using ten years ago. Modern Perl can compete with any of the features of any other dynamic language.

By al means, try to get the time to rewrite your crufty old systems. But rewrite them in Modern Perl. You’ll enjoy it and you’ll be really productive.

p.s. I should point out that I’m not talking about any specific client here. This is based on conversations that I’ve had at various companies over the last couple of years and also discussions with many developers in many pubs.

Send to Kindle

A Subway Metaphor

Many years ago I read a science fiction story which has always stayed with me – although I’m buggered if I can remember the title or the author.

It was set in the not too distant future. Another new line was about to be opened on the New York City Subway [In the comments Rozallin points out that it was, in fact, probably Boston and not NYC]. Mathematicians were warning that the line shouldn’t be opened as every new line increased the complexity of the network and they had calculated that opening this particular line would push the network over some limit and would make it theoretically unsolvable. They worried that the safety of passengers couldn’t be guaranteed if they were travelling on an unsolvable graph.

Of course, the mathematicians were ignored. And, of course, trains started going missing soon after the line was opened. And that’s where our hero (a kind of topological Indiana Jones, if I recall correctly) came in.

For some reason, that’s the image that sometimes pops into my head when I’m working on large application that has had random pieces of code added to it by various people over long periods of time. I worry that the system will eventually become so complex that any train (or, more likely, CPU) that is set running on it will vanish into the depths of complexity, never to be seen again.

I had that feeling particularly strongly this afternoon. This system really needs to be brought under control.

Send to Kindle

Moose or No Moose

I’ve known about Moose for some time.The first time I talked about it in a training course was at the Teach-In back in the summer of 2007. It’s been part of my training courses ever since.

But even though I was telling people about Moose in my training courses, I wasn’t really making use of it in my own code. Obviously as a freelancer, in my day-job I’m constrained to using whatever technologies my clients are using and I have yet to be paid to work on a project that is already using Moose (although I’ve suggested that a few clients switch to it).

That leaves my own code. Which is largely my CPAN modules. Until recently I hadn’t used Moose for any of them. The first one I released that used Moose was Guardian::OpenPlatform::API. That was a new module which used Moose right from the start. But I knew that eventually I’d want to go back and refactor my existing modules to use Moose wherever it was appropriate.

Having gone to YAPC::Europe this year, I was subjected to another week of people telling me face to face just how cool Moose was. So I decided that it was time to bite the bullet and start refactoring.

The next module I tried was Parse::RPM::Spec. I chose this for two reasons. Firstly, it’s very much an attribute-driven module. Apart from the initial parsing of the spec file, objects of this class exist simply to return the values of their attributes. This makes it a great match for Moose. In fact converting it to use Moose was largely a case of removing code. The second reason for choosing it was more pragmatic – as far as I know no-one is using the module so if I broke anything I wouldn’t have hordes of angry users on my back.

Impressed by how easily that conversion was I moved on to Array::Compare. This module holds a special place in my heart as it was my very first CPAN module. I don’t think it’s a particularly useful module. It’s algorithm is pretty basic and other than the project that I originally wrote it for I’ve never used it in any production code. I often use it to try out new techniques. I released version 2.00 on August 9th (the change of implementation seemed to justify bumping the major version number).

Yesterday I got an RT ticket asking me to stop using Moose. The ticket is pretty clear that for several uses (it specifically mentions command line usage) the extra overhead added by Moose leads to an unacceptable performance hit.

I’m not sure which way to go on this. As a developer I like using Moose. Moose makes it much easier to write object oriented code in Perl. And I think that over the next year or so more and more CPAN developers will be using Moose in their code. Already if you’re writing something reasonably complex in Perl there’s a good chance that you’ll be using a module that uses Moose. As time goes on the percentage of Perl code that relies on Moose will increase. But if it really imposes an unacceptable performance hit for smaller applications, do I really want to force developers into using Moose sooner than they want to?

I think I’m going to put on hold my plans to move stuff to Moose until I’ve thought this through a bit more. But I’d be interested in hearing other people’s opinions. If you’re a CPAN author, are you planning to move your modules to Moose. And if you’re an application developer, have you started to avoid CPAN modules which force you to use Moose?

Let me know what you think.

Update: Well, didn’t this entry start a lot of discussion? As well as the comments here, there have been a number of other posts that reference my post. Here are the ones I’ve seen (in no particular order):

I’ll add more as I come across them. Of course, the more discussion I see, the more unclear my decision becomes.

But thanks for the interest. The discussion has been fascinating.

Send to Kindle

What is Wrong With this Picture?

I’ve just found a number of subroutines defined this way in the code that I’m working on.

I discovered the problem because I started getting errors about “too many parameters”. I knew what the problem was (the empty prototype) but it took a couple of minutes of head-scratching before I realised why it had been working before my changes.

Then I realised.

I have a dislike of “unnecessary” &s on subroutine calls. So almost without realising, I had removed them from the calls to these functions.

A few lessons have been learned.

Lesson 1 (for the original author of this code): Prototypes will trip you up. Do not use them.

Lesson 2 (for me): Ampersands aren’t always as pointless as they appear. They may be masking bugs in the code.

Send to Kindle