OpenSource++ - How to contribute to a project without knowing a damn bit about it

I assume most of you know ACT (A Conference Toolkit), the venerable piece of software that runs most Perl conference websites. It's quite old (I think the current version dates from ~2004). It's definitely older than Catalyst, DBIx::Class and Plack. So you can image that it's internals are ... unique (as most internals of websites from the pre-framework area are).

At YAPC::Europe 2013 in Kiew I was trying to get speakers to add links to their slide to a wiki page to make it easier for attendees (and non-attendees) to get to them. Somebody (I think it was rGeoffrey) told me that this was already implemented in ACT. And indeed there is a page called Proceedings that lists all talks and includes links to the slides, if the author has published them.

That's nice, but I'm way too lazy to read through this page and figure out which talks have slides and which don't. So I decided to add that feature.

Getting the source

It's easy to get the source of ACT, as it lives on github. As I planned to add a feature, I decided to fork the repo.

After a few seconds waiting, the forking was done and I now had a copy of ACT in my github.

Now I could clone the repo:

~/perl/other$ git clone git@github.com:domm/Act.git

How to contribute to a project without knowing a damn bit about it or being able to run it

ACT comes with Installation Manual, but it requires mod_perl and a Postgres DB. Which is way to much hassle to set up during a conference. So I decided to hack "blind" (or "dry"?).

Start hacking

The first thing you should do when hacking on anything is to start a new branch:

~/perl/other/Act$ git checkout -b slides_page
Switched to a new branch 'slides_page'

As I had no idea how to implement the feature I wanted, I tried to find something similar, in this case the proceedings page:

~/perl/other/Act$ ack -i proceedings

This found two relevant files:

lib/Act/Dispatcher.pm
29:    proceedings     => 'Act::Handler::Talk::Proceedings',

lib/Act/Handler/Talk/Proceedings.pm
1:package Act::Handler::Talk::Proceedings;
46:    $template->process("talk/proceedings");
82:Act::Handler::Talk::Proceedings - show proceedings
86:Show proceedings: all talks in a big list, with the useful details.

It seems that each action has to be registered in Act::Dispatcher and implemented in a handler. So I just added a new entry to the dispatch:

~/perl/other/Act$ git diff 02a353~..02a353
diff --git a/lib/Act/Dispatcher.pm b/lib/Act/Dispatcher.pm
index 3dcd171..77118ff 100644
--- a/lib/Act/Dispatcher.pm
+++ b/lib/Act/Dispatcher.pm
@ -27,6 +27,7 @ my %public_handlers = (
     news            => 'Act::Handler::News::List',
     openid          => 'Act::Handler::OpenID',
     proceedings     => 'Act::Handler::Talk::Proceedings',
+    slides          => 'Act::Handler::Talk::Slides',
     register        => 'Act::Handler::User::Register',
     schedule        => 'Act::Handler::Talk::Schedule',
     search          => 'Act::Handler::User::Search',

Now let's set up a new package by copying a similar one

~/perl/other/Act$ cp lib/Act/Handler/Talk/Proceedings.pm \
                     lib/Act/Handler/Talk/Slides.pm

Inside we find one relevant method, called handler, which (sort of) looks like this:

sub handler {
    # retrieve talks and speaker info
    my $talks = Act::Talk->get_talks( conf_id => $Request{conference} );
    for my $talk (@$talks) {
       # make the User object for the speaker
       $talk->{user} = Act::User->new( user_id => $talk->user_id );

       # default language
       $talk->{lang} ||= $Config->general_default_language;

       # make a summary of the abstract (some people write long abstracts)
       my $abstract = text_summary($talk->abstract, 400);
       $talk->{chunked_abstract} = Act::Abstract::chunked($abstract);
    }

    # sort talks
    # ..
    # process the template
    $template->process("talk/proceedings");
}

The most interesting line being

my $talks = Act::Talk->get_talks( conf_id => $Request{conference} );

which uses a method (or function?) called get_talks with some options. If ACT would use DBIx::Class, it would now be trivial to alter the query (at least if you know the schema). But Act uses a custom written DBI abstraction layer, which I know nothing about.

I tried to ack get_talks but after 10 minutes of hunting through files and reading code without producing any results I decided to quit this approach and go for a more hackish, not so performant solution:

~/perl/other/Act$ git diff c908f71d2~..c908f71d2
diff --git a/lib/Act/Handler/Talk/Slides.pm b/lib/Act/Handler/Talk/Slides.pm
index d849ddd..a6f4810 100644
--- a/lib/Act/Handler/Talk/Slides.pm
+++ b/lib/Act/Handler/Talk/Slides.pm
@ -12,16 +12,17 @ use Act::User;
 sub handler {
     # retrieve talks and speaker info
     my $talks = Act::Talk->get_talks( conf_id => $Request{conference} );
+    my @filtered_talks;
     for my $talk (@$talks) {
+       next unless $talk->{url_talk}; # TODO this should move into get_talks
+       push(@filtered_talks,$talk);
+    }

I just get all the talks from the DB and filter out all talks that don't have a url_talk (i.e. that don't have slides). Of course this is not very elegant and results in lots of data being transferred just to be discarded later.

But: Any person that has better knowledge of ACT than I do can convert my hack to a proper solution!

The rest of my changes where minimal: setting up a new template, and using this template in the handler.

Sending the patch

I now only had to publish my branch (I'm to lazy/dumb to remember the correct git, so I use this script)

~/perl/other/Act$ git publish-branch

And send off the pull request.

Which got merged a few minutes later, as Maddingue was sitting a few meters away from me...

And the moral of it is

Even if you do not completely understand the code your working on (or in fact only barely understand it, as in my case..), you can still try to send in a patch. The worst thing that will happen is that you're contribution is ignored. The likely thing to happen is that the maintainer will take your patch, fix it & release it.

P.S.: This post is no way meant as criticism on Act. It's a nice piece of software, it runs a lot of Perl events and I'm very thankful it's available (as a attendee, speaker and organizer!). The code is a bit old, but I can understand that nobody of the current maintainers has the tuits to rewrite it using more modern tools and frameworks.