Will SWAG for food

March 2, 2011

Why is it that when I am asked to estimate a project, I switch into abused-dog mode? My first instinct is to dive under the desk and whimper, which I promptly suppress in favor of other, hopefully more productive approaches.

So the last time I was asked, I stewed about it for 24 hours, talked with management-experienced friends, then finally did the sensible thing: I went to a colleague and ‘fessed up. “I’m not that good at this. And not only am I not good at this, I can’t calm myself enough to make myself good at this. May I get some help?” Why certainly. So yesterday we started to break down my project into finer detail. I drew up a spreadsheet with tasks, estimated each on a story point scale, added it up, and multiplied by 3 to account for the fact that I’m not Donald Knuth. I added a column for actual time, and hopefully, over time I will get an idea of the value of my own personal human coefficient, which I suspect will be rather high.

I reviewed Andy Lester’s Preventing Crisis talk, and asked my former colleague Buddy Burden for the story point scale in use at Rent.

Story Points The Buddy Scale The Dave Scale
dink “We’ve already spent more time talking about it than it would take to just do it.” An issue added that is quick to implement i.e., < 1 hour, equivalent to .25 story points
1 “Pfft. That’s nothing.” hours
2 “That’s not too bad …” hours to a day (or two)
3 “Not too awful, but non-trivial.” a few days

5 “This is some real work.” days to a week (or two)
8 “This is surprisingly difficult.” a few weeks
13 “This really sucks.” weeks to months
21 “There’s no way one person could do this by themselves.” weeks to months for multiple people
40 “This is a major project.” months for multiple people
100 “If they truly understood how heinous this was, they wouldn’t want to do it any more.” months for a lot of people


Web::Scraper

February 27, 2011

Lately I’ve been using the nifty Web::Scraper by the prolific Tatsuhiko Miyagawa. It exposes a compact DSL of three words, process, process_first and result, to scrape sites based on XPath expressions or CSS selectors:


use Data::Dumper;
use Web::Scraper;
use URI;

# Find the <title> element and place its content
# in a hash reference with the key 'title'

my $scraper = scraper {
process '//title', title => 'TEXT';
};

my $data = $scraper->scrape(
URI->new('http://www.google.com')
);

warn Dumper $data;

Gets you

$VAR1 = {
'title' => 'Google'
};

You can also have it return an arrayref for an element, pass in callbacks, or nest scrapers.

I forked the code and added a hashref option, nice when paired with a callback that returns a hash.

scraper (a disguised constructor) and the keywords are exported into the caller’s namespace. If the potential for collision concerns you, wrap up scraper instantiation in a separate module.

The documentation is a bit thin, so in addition check out Miyagawa’s presentation slides.


First foray into Moose

February 26, 2011

As a startup’s sole Perl programmer I have been feeling the pressure to get things done more quickly. Whipping up a codebase from scratch, or from a chicken-scratch prototype, is very different from propping up a brittle hulking legacy codebase. I began to feel limited by Perl’s object model simply because of all the keystroking and the attention to implementation details. So yesterday I gave Moose a little try.

A well-designed toolkit always gives the new user one very useful thing right away, a small but immediate reward for the effort of trying out a new way of doing things. Moose does this with the keyword has. Describe your attributes in excruciating detail and poof! you’ve done away with mounds of keystroking. Very nice. Already a quick little boost before lunchtime, and this time not from my coffee cup.

I also noticed another side benefit. Writing classes declaratively is an aide to thinking more abstractly. The little word has puts the emphasis directly on the interface. A language and its user have a symbiotic relationship–the user writes in the language and the language guides the user’s thinking. Moose enhances Perl’s ability to lead, follow or get out of the way at the right times by letting you shift gears to greater abstraction. I found this very pleasant.


!=

February 25, 2011

Information is not knowledge. Knowledge is not wisdom. Wisdom is not truth. Truth is not beauty. Beauty is not love. Love is not Perl. Perl is THE BEST.

D’apr├Ęs Frank Zappa, who originally said this of music.


Still around

February 25, 2011

This past year I emigrated to France and married another Perl hacker. I recently got a new job as a Perl programmer, this time in Paris, so I’ll post again from time to time.


Coder Girl

October 18, 2009

Yes!

October 17, 2009

It is my pleasure to announce that after much fooling around with XS, I am now reading temperatures from the device with Perl.

ok 1 - use Vernier::GoTemp;
ok 2 - The object isa Vernier::GoTemp
# 27.4995159422979
# 27.4995159422979

That is the ambient temperature in Celsius.

Update: My ten-year-old son and I had a grand time measuring temperatures under our armpits, behind our knees, in front of the fan, and in glasses of ice, lukewarm and warm water.


Bus error

October 17, 2009

A phrase I see occasionally after a C-programming oopsy.


Devel::Peek

October 17, 2009

Today I belatedly discovered the usefulness of Devel::Peek.

While hacking on the newly-rebaptised Vernier::GoIO I found that get_device_info was handing me back garbage. Using Devel::Peek helped me pinpoint the problem more quickly.

get_device_info should return an array consisting of device name, vendor ID and product ID; the former is a string in hex and the latter integers required by HID USB.

Devel::Peek to the rescue. At the top of Vernier/GoIO.pm:

use Devel::Peek qw(Dump);

and in the offending routine, a strategically-placed call to Dump:

sub get_device_info {

    my $handle = shift;

    my @info = Sensor_GetOpenDeviceName($handle);

    Dump(\@info);

    die "No device info found for $handle!" unless @info;

    return (
        'name'       =>  $info[0],
        'vendor_id'  =>  $info[1],
        'product_id' =>  $info[2],
    );
}

Running a test nets me this output:

SV = RV(0x82603c) at 0x86590c
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x8633bc
  SV = PVAV(0x864684) at 0x8633bc
    REFCNT = 2
    FLAGS = (PADBUSY,PADMY)
    IV = 0
    NV = 0
    ARRAY = 0x30b9e0
    FILL = 2
    MAX = 3
    ARYLEN = 0x0
    FLAGS = (REAL)
    Elt No. 0
    SV = PV(0x849ad4) at 0x866074
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x304eb0 "0x1d100000"
      CUR = 10
      LEN = 12
    Elt No. 1
    SV = IV(0x80d3ac) at 0x865954
      REFCNT = 1
      FLAGS = (IOK,pIOK)
      IV = 8388740
    Elt No. 2
    SV = IV(0x80d380) at 0x8660c8
      REFCNT = 1
      FLAGS = (IOK,pIOK)
      IV = 8388740

An array ref with three elements. Looks good. But those last two values? Not what I had in mind. I should get 2295 and 2, respectively.

perlguts gave me a clue:

Despite their suggestions in earlier versions of this document the macros (X)PUSH[iunp] are not suited to XSUBs which return multiple results. For that, either stick to the (X)PUSHs macros shown above, or use the new m(X)PUSH[iunp] macros instead; see “Putting a C value on Perl stack”.

I’d pushed three scalars on the stack, the first using the macro XPUSHs and the next two with XPUSHi:

            XPUSHs(sv_2mortal(newSVpv(name, strlen(name))));
            XPUSHi(sv_2mortal(newSViv(vendorId)));
            XPUSHi(sv_2mortal(newSViv(productId)));

I changed the XPUSHi to XPUSHs as advised by perlguts, re(generated|compiled|tested) and lo! correct return values.

SV = RV(0x82603c) at 0x86590c
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x8633bc
  SV = PVAV(0x864684) at 0x8633bc
    REFCNT = 2
    FLAGS = (PADBUSY,PADMY)
    IV = 0
    NV = 0
    ARRAY = 0x30b9e0
    FILL = 2
    MAX = 3
    ARYLEN = 0x0
    FLAGS = (REAL)
    Elt No. 0
    SV = PV(0x849ad4) at 0x866074
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x304eb0 "0x1d100000"
      CUR = 10
      LEN = 12
    Elt No. 1
    SV = IV(0x80d334) at 0x865954
      REFCNT = 1
      FLAGS = (IOK,pIOK)
      IV = 2295
    Elt No. 2
    SV = IV(0x80d3ac) at 0x8660c8
      REFCNT = 1
      FLAGS = (IOK,pIOK)
      IV = 2

perlguts has this to say about why those two integer values were identical:

The following code will not do what you think:

 XPUSHi(10);
 XPUSHi(20);

This translates as “set TARG to 10, push a pointer to TARG onto the stack; set TARG to 20, push a pointer to TARG onto the stack”. At the end of the operation, the stack does not contain the values 10 and 20, but actually contains two pointers to TARG, which we have set to 20.

Okay then. Point taken, and mental note made to study
“Putting a C Value on the Perl Stack” more closely.


Typemapping

October 11, 2009

Today’s XS problem was solved with a tweak of the typemap.

I wrote a constructor for the Go! Temp device class Vernier::GoTemp that, amongst other things, ‘opens’ the device; that is, establishes communications with and initializes it.

The C prototype is

GOIO_DLL_INTERFACE_DECL GOIO_SENSOR_HANDLE GoIO_Sensor_Open(
        const char *pDeviceName,        
        gtype_int32 vendorId,   
        gtype_int32 productId,  
        gtype_int32   strictDDSValidationFlag);

and the XSUB is


GOIO_SENSOR_HANDLE
GoIO_Sensor_Open(pDeviceName, vendorId, productId, strictDDSValidationFlag)
        const char *    pDeviceName
        gtype_int32     vendorId
        gtype_int32     productId
        gtype_int32     strictDDSValidationFlag

The make test error I got was

pDeviceName is not of type const charPtr at /Users/zrusilla/proj/goio/Vernier/blib/lib/Vernier/GoIO.pm line 150.

The device name is a hexadecimal number 0x1d100000, so I thought the integer part of the scalar was being passed long to the XSUB, which howled in protest. How to fix? With a tweak of the typemap.

The previous entry for a const char *was
const char * T_PTROBJ

The typemap documentation tells me:

T_PTROBJ
Similar to T_PTRREF except that the reference is blessed into a class. This allows the pointer to be used as an object. Most commonly used to deal with C structs. The typemap checks that the perl object passed into the XS routine is of the correct class (or part of a subclass).

The pointer is blessed into a class that is derived from the name of type of the pointer but with all ‘*’ in the name replaced with ‘Ptr’.

Ah, so that’s the problem. When the C header says char *, it means char *. So I changed the typemap entry to a T_PV, which is a plain old char *:

const char * T_PV

rebuilt and tested. And all tests pass.