sabato 24 gennaio 2015

Perl, printf and qw to rescue!

When dealing with fixed/padded strings, nothing is better in my opinion of the printf family of functions.
However, the printf has a couple of problems when trying to format complex data, especially if compared to pack().
The first problem is that the formatting string could result very hard to read; for instance consider the following one:

qq(%-4s%1s%09d%1s%-50s%-50s%1s%08d%-4s%-16s%-100s)

The second problem is that it cannot handle easily errors in field types, and this often happens when cycling thru a file and formatting each line according to a specific formatting string. Consider again the above formatting string: what happens if the third field is not a valid number on each line of the file you are processing? Perl simply compains, or better, printf() complains about an error.

One solution I found that can help solving both problems is to dynamically build the formatting string from an array of single atoms. So for instance I specify the above formatting string as follows:

$format_specs = [ qw(%-4s %1s %09d %1s% -50s% -50s %1s %08d %-4s %-16s %-100s) ];

and then later I use something like:

printf join '', @{ $format_specs }, @fields;

Why should it be better than using a single pre-formatted string?
Well, first of all, having extracted each formatting pattern into an array allows for better readibility (I can even add comments to each atom to remember what it means). Second, and most important, I can check each field read from the input file and see if it comply the formatting atom. For instance, to check for a number:

for my $index ( 0..$#format_specs ){
  warn "Error on field $index, expected $format_specs[ $index ]\n" 
     if ( $format_specs[ $index ] =~ /d/ && $fields[ $index ] !~ /\d+/ );


Of course it is possible to build a more robust checking around each field, but the usage of an array of formatting atoms allows for a quick and iterative checking of the field nature, as well as ad-hoc error reporting.

venerdì 16 gennaio 2015

printf and the wrong attitude: an experience

I'm so used to the way the normal print operator works in Perl that I did a silly mistake using the printf function with the same attitude: a full list of arguments.

The buggy line was like the following:

printf $format_string, @data, "\n";

Can you see the error?
Well, the new line at the end is not likely to be printed, and it was not in my case. The problem is that everything that follows the format string is managed as an argument to the format string itself. Therefore, the format string must have a placeholder for the new line charaters, as in:

$format_string = "%d %s %c ....%s";

In my case I was not placing the last %s in the format string because I used the format string itself to manage how many data to extract from the array of elements, that is something like:

printf $format_string, @data[ 0..$hint_from_command_string ], "\n";

And in order to waste a little more time, I was trying to figuring it out on a terminal that was wrapping the line length where the new line should have been, making the illusion I was looking at separated lines.
Of couse using a good text editor or some tool like head revealed I was looking at something very different: a whole line.
And that helped me finding the bug and moving the new line character into the format string at the very last moment:

printf "$format_string\n", @data;

Shame on me!

mercoledì 14 gennaio 2015

CPAN Pull Request: Janaury done!

My first attempt in the CPAN Pull Request Challenge was the production of a patch listed here.
After a few days I asked the original maintaner to close the pull request, and then I submitted another one with the right set of commits here.
And it got merged!

Well, my pull request was quite small and, after all, easy. I would not define it entirely monkey-typing patch, but it is pretty much what I've done. And that is right to me: I'm not searching to demonstrate I'm a killer Perl programmer at the risk of breaking some well used module!

So what did I learn from my first pull request work?
A lot of things after all, and a lot of things that I should always keep in mind when collaborating to other projects.
The first thing is public embarassment: in my first pull request I did place a commit that was a wrong change to the module (see here). While doing it, I was sure that the original developers are smarter than me, but I was trying to simplify the code anyway and it seemed to me that using Exporter instead of an hand-written import method was the right way. But I was wrong!
And despite being wrong, I was teached an important lesson here: I should have checked outside of module (tests) to see who was using the import method in non-ordinary ways. And so I learned on how to use better grep.perl.org.
Another thing I learnt is that I should not produce more work for the original maintainer: each commit must describe well and in detail what the changes are, explaining also the motivations that lead me to such changes. This will be helpful for future referneces and discussions, and will speed-up the approval of the patch.
And of course, I re-learnt to use git branches. Each development should be made on a separated branch, and each branch should include only a set of related commits.

How did I worked on this pull request?
Being the module assigned to me quite simple (a single file), I started reading the source code and looking around for "well-known" problems. Warnings and hand-written import sounded good candidates for first fixes, and perlcritic can help at this stage. Of course, both of above do not require changes on a stable and deeply used module, so I had to throw away commits.
Then I read the documentation, finding that a few regular expressions were not matching what was in the docs, and therefore working around them to fix and to make the documentation coherent with the code. This is not simple and cannot be automated.
Each change was tested again the test suite, and here tools for test coverage can be very useful to find out other ways to improve the dist.

I'm happy to see I was able to produce a contribution, even if small.
And I'm glad to see I'm learning more and more things and methodologies.

Il rinnovo della carta prepagata che non va come dovrebbe...

Ecco un esempio di cattiva informatica, unita ad un cattivo servizio all'utente.
Dovevo rinnovare la mia carta prepagata PostePay, e ben lieto, mi sono attivato perché mi venisse recapitato il tutto direttamente a casa mia.
L'idea è semplice: le Poste inviano con due lettere differenti la nuova carta e il pin, dopodiché si attiva telefonicamente la nuova carta, annullando immediatamente la vecchia e trasferendo il credito residuo.
Peccato che tutto questo giro sia fallimentare.
Il primo problema è che sia il pin che la nuova carta non vengono inviate tramite raccomandata, bensì con posta ordinaria.
Inoltre il tutto dovrebbe essere ricevuto entro 30 giorni, mentre nel mio caso ce ne sono voluti piu' di 45. Considerato che non si tratta di un'azienda che richiede servizio alla posta, bensì tutto il procedimento è gestito da Poste Italiane, non capisco a cosa siano dovuti questi ritardi.
Terzo problema: se, come nel mio caso, il documento di identità specificato all'atto di stipula della precedente carta è scaduto occorre recarsi nell'ufficio postale piu' vicino per una identificazione de-visus e l'aggiornamento dei dati del documento. Questo nasconde in realtà due ulteriori problemi: anzitutto la mia carta di identità (o meglio la copia che aveva Poste Italiane) risultava scaduta all'atto della richiesta della nuova carta, e quindi mi sarei aspettato che qualcuno mi informasse circa l'impossibilità a richiedere telefonicamente la nuova carta. Inoltre la carta, essendo stata richiesta per telefono, non puo' essere attivata dall'ufficio postale, e quindi dopo essermi recato in ufficio, aver fatto la fila e aggiornato dati e documenti, son dovuto tornare a casa e attendere al telefono che qualcuno attivasse la carta.

Riassumendo non si capisce perché Poste Italiane non ti avvisi subito dell'impossibilità a procedere con la richiesta (documenti scaduti nel mentre) e di come anche questo servizio, che dovrebbe farti evitare la fila allo sportello, alla fine richieda comunque ore di attesa fra uffici e telefono.

domenica 4 gennaio 2015

My first (tiny) pull request

So I spent a few hours studying my first module, the Test::Pod, and produce a few commits to make some small changes to the existing code in order to improve it (or at least, I hope so). The pull request can be found here.

Despite these small changes, I'm detailing here the approach I will try to use as a checklist during the challenge, in order to make it a path for learning and for not-breaking things:
  • run all the tests in the distribution, in order to see if there is any failure (it should not be), and if so, start from such tests;
  • search for open issues/tickets, and see if any of them is good for work on;
  • read the dist documentation, see if it contains typos and/or errors and/or missing parts;
  • read the code and see if there is something obvious that can be improved (e.g., use strict);
  • inspect the code and see if it does what the documentation says.
Of course, it is required to iterate on each step and, of course, to test every single change against the test suite (and maybe provide a new test for that). 
It is important to not produce work for the original author, and therefere:
  • do not change code only because I would have written it with a different name, logic, conditional or alike. Try instead to make code more concise keeping readibility;
  • do not provide code that breaks and test every single change at least for what it is possible and for what is the understanding of the problem and of the language;
  • commits must have a good description of every single change, so that the original author can understand what was the intention of every change;
  • keep commits as small as possible.
I'll refine the above checklist as I go on the challenge.
In the meantime, a few utilities can help in the work, most notably perlcritic, perltidy and Devel::Cover and Devel::NTYProf or similar.

venerdì 2 gennaio 2015

2015 CPAN Pull Request Challenge

I'm going to participate to the 2015 CPAN Pull Request Challenge, an effort to make developers join the Perl community and contribute back some code.
The idea is simple and beautiful: each month you are assigned a random CPAN dist and have to inspect, study, read it and propose something (a pull request) to improve it. It could be a bug fixing, ticket issue, code optimization, documentation, and so on. Everything that can be accepted back from the original author.

I'm a little nervous: it has been a lot since I do not program day by day using Perl, but I'm quite happy to have the opportunity to learn something from the masters and, most notably, to contribute stuff back to this great community.

Let's see wat will happen!