The other day on Hacker News, there was a good discussion of Avdi Grimm‘s talk on how to write Confident Code given at this year’s Ruby Midwest. He covers four areas: gather input, perform work, deliver results and handle failure. Here are links to the code example showing the initial, timid and final, confident code. I’ll just cover the input gathering step because I think embedded type constraints is vital for improving coding efficiency and minimizing boilerplate.
Most of this can actually be done using something like Ruby’s Doodle. It does not appear that Doodle is very popular yet (21 all time messages in the mailing list) though I think it would be good if it were more so.
More popular is Stevan Little‘s Moose for Perl which has 28 named contributors. While I like to read about many technologies I generally like to use more mature and popular technologies than less so I’ve been using Perl’s Moose and haven’t coded with Doodle yet.
To show how Moose is powerful, let’s write the Confident Code example in Perl
Confident Code in Moose
I whipped this up for discussion so it can definitely be refined, however, it should get the ideas across. Here are some things that are covered:
- Input Validation: Inputs are typed and given default values in both attributes (e.g. width as an Integer with default 40) and methods (e.g. messages as an ArrayRef of Strings – ArrayRef[Str])
- Separation of Concerns: attributes and methods are conveniently separated for easier maintenance and testing
- Output: IO::All is used for output, defaulting to STDOUT (i.e. ‘-’)
use MooseX::Declare;
class CowsayTheMooseway {
use Capture::Tiny qw(capture_merged);
use IO::All;
use Log::Log4perl qw(:easy);
Log::Log4perl->easy_init($INFO);
has width => ( isa => 'Int', is => 'rw', default => 40 );
has eyes => ( isa => 'Str', is => 'rw', default => '' );
has cowfile => ( isa => 'Str', is => 'rw', default => 'moose' );
has destination => ( isa => 'Str', is => 'rw', default => '-' );
method command {
my $command = 'cowsay -W ' . $self->width;
$command .= ' -e '.$self->eyes if $self->eyes;
$command .= ' -f '.$self->cowfile if $self->cowfile;
}
method say (ArrayRef[Str] $messages) {
my $command = $self->command;
my $output = capture_merged {
system "$command $_" for @$messages;
};
$output > io $self->destination;
INFO "wrote to ".$self->destination;
}
}
Note how the input attributes and methods are all separated cleanly with their own input types.
Here’s how to run the class:
use CowsayTheMooseway;
CowsayTheMooseway->new(
destination => 'moo.txt'
)->say([
'Psst...Want More Confidence?',
'Here is How',
'Moose This Way'
]);
And the results:
______________________________
< Psst...Want More Confidence? >
------------------------------
\
\ \_\_ _/_/
\ \__/
(oo)\_______
(__)\ )\/\
||----w |
|| ||
_____________
< Here is How >
-------------
\
\ \_\_ _/_/
\ \__/
(oo)\_______
(__)\ )\/\
||----w |
|| ||
________________
< Moose This Way >
----------------
\
\ \_\_ _/_/
\ \__/
(oo)\_______
(__)\ )\/\
||----w |
|| ||
Let me know what you think. Should this type of coding be done in Ruby? Is Doodle the way to go or is there something else? Can the Perl code be improved?





