July 2011 Archives

If you can't make money, at least have fun.

There's a saying: "If you can't make money, at least have fun." My open source projects have never earned a profit, but they've been enormous fun.

They've put me in the position to meet a lot of great people and go to interesting places. It's hard to imagine having more fun than I did speaking at Perl Oasis and YAPC::NA this year. If anyone releasing projects in other languages has more fun than this, how do they survive?

But giving away software is only fun when people use it. Otherwise it's just saving public backups or something.

So hearing that DomainSponsor's distributed server architecture uses one of my modules made my weekend. It was an awesome feeling, and it put me in the mood to update five distributions in the past couple days.

And write a blog post, which you're reading. Thanks, by the way.

So if you're using CPAN modules (and can talk about it, of course) let us authors know. Because most of us aren't making money at it, and you'll help us have more fun and release more code despite that.

Reducing Documentation's Technical Debt

Documentation is a social asset, but it's balanced by a technical debt. Documentation describes code that changes over time. As the code changes, so must the docs.

I want to write good documentation for my Perl distributions, but my standard of "good" documentation requires a lot of effort to write and maintain. I'm working on Pod::Plexus to make it easier. It doesn't replace anything, as far as I know. In fact, I've begun using it with Pod::Weaver in my Reflex distribution.

For example, I tend to write modular, cross-referenced code. Everything but the most superficial interfaces is used somewhere else in the distribution. I'd rather not contrive usage examples, so why not reuse parts of the distribution in the documentation? So Pod::Plexus includes an "=example" directive to insert live code into the documentation.

One of my pet peeves is hierarchical documentation. It's easy to document a subclass by saying "everything else (which I may or may not list here) is documented in this base class". On the down side, that's terrible for first time users. What does the module provide? Which ancestor documents which method? So tonight I added an "=include" directive to insert live documentation from another place.

Here's an example of Pod::Plexus markup. Output follows. It uses "=example" to create a synopsis from the module's live implementation. "=include" imports the description from a nearly identical module. Pod::Plexus includes some templating magic, so [% doc.module %] expands to the module being documented.

package Reflex::Eg::Inheritance::Plain;

use warnings;
use strict;
use base 'Reflex::Timeout';

sub on_done {
    shift()->reset();
    print scalar(localtime()), " - Subclass got timeout.\n";
}

1;

__END__

=pod

=abstract Inheriting a Reflex timer with plain Perl.

=head1 SYNOPSIS

=example Reflex::Eg::Inheritance::Plain

Usage:

    perl -M[% doc.module %] -e '[% doc.module %]->new(delay => 1)->run_all'

=head1 DESCRIPTION

This module is nearly identical to Reflex::Eg::Inheritance::Moose.
It only differs in the mechanism of subclassing Reflex::Timeout.

=include Reflex::Eg::Inheritance::Moose DESCRIPTION

=cut

Here's the output as promised. You'll notice that "=abstract" becomes a NAME section. Had this not been a test, Pod::Weaver would have added several other boilerplate sections.

package Reflex::Eg::Inheritance::Plain;

use warnings;
use strict;
use base 'Reflex::Timeout';

sub on_done {
    shift()->reset();
    print scalar(localtime()), " - Subclass got timeout.\n";
}

1;

__END__

=pod

=head1 NAME

Reflex::Eg::Inheritance::Plain - Inheriting a Reflex timer with plain Perl.

=head1 SYNOPSIS

    package Reflex::Eg::Inheritance::Plain;

    use warnings;
    use strict;
    use base 'Reflex::Timeout';

    sub on_done {
        shift()->reset();
        print scalar(localtime()), " - Subclass got timeout.\n";
    }

    1;


Usage:

    perl -MReflex::Eg::Inheritance::Plain -e 'Reflex::Eg::Inheritance::Plain->new(delay => 1)->run_all'

=head1 DESCRIPTION

This module is nearly identical to Reflex::Eg::Inheritance::Moose.
It only differs in the mechanism of subclassing Reflex::Timeout.

Reflex::Timeout objects normally go dormant after the first time they
call on_done().

Reflex::Eg::Inheritance::Plain implements a simple periodic timer by subclassing and
overriding Reflex::Timeout's on_done() callback.  The act of finishing
the timeout causes itself to be reset.

Since this is an example, the subclass also prints a message so it's
apparent it works.

This is a relatively silly exercise.
Reflex::Interval already implements a periodic interval timer.

=cut

In a future installment, I'll talk briefly about how "=index REGEXP" creates an index of all the distributed modules matching a regular expression.

About Rocco Caputo

user-pic Among other things I write software, a lot of which is in Perl.