I’m proud to announce version 1 of nychealthratings.com. I put in many late nights hacking over the last month in getting it done. It’s essentially a website with two tools.
The initial tool I wrote was a Javascript bookmarklet that integrates new york city restaurant inspection results with the restaurant landing pages of yelp.com, citysearch.com, menupages.com and opentable.com. The aim was to complement peoples search efforts by integrating health inspections data with the sites they already use. To use the bookmarklet go to nychealthratings bookmarklet follow the directions and watch the video. This tool was my entry into nyc big apps 2.0. If you like what I’ve done please vote for me here.
The bookmarklet was a great starting point to something that I think could be much bigger. I think it’s just as important that people see this data when making dining decisions as reading reviews on Yelp! or Zagats. It’s data that people want and need. So the logical next step was to build a google maps search application which makes that possible. With the google maps app you can search for restaurant inspections for all 22,485 restaurants in New York City. You can search by type of restaurant, by name, location, and filter by inspection grade.
The key is to make the data pervasive and accessible. So next on my agenda is to build Android and IPhone applications. I’ll start with Android because I have experience building Android applications. Much of the backend components for the maps application can be reused.
Immediate enhancements to the site will be an upgrade of the current search technology. I’m currently using mysql full text search indexes which although easy to setup, they are incredibly limited in the types natural language processing issues that come up when building a search application. I’m currently evaluating using Solr, Sphinx and a product called ElasticSearch.
I’ve been thinking about what’s motivated me to do this. I’m not getting a dime. I’m doing it because I like to hack and I’m damn good at it.
My biggest gripe about Perl has always been the lack of functional prototypes and method signatures. The concept of method signatures is not a revolution it’s been around forever, almost every programming language I can think of off the top of my head has it in some form. Having to unpack @_ time and time again is just such a waste of keystrokes. Not only that there are multiple ways to do something so basic. (Shift, copy the list to lexical vars, direct access in $_[i] etc). It’s surely been the source of a number of bugs and something every Perl programmer needs to be conscious of.
My main argument for method signatures is it reduces bugs and it documents your code without having to write documentation. Its declarative, it does what it says and says what it does. Plain and simple no guessing. As most Perl programmers are aware Devel::Declare is a module that has added the ability to extend Perl 5 the language without source filters. There are several really cool modules that have been developed on top of Devel::Declare. MooseX::Declare and MooseX::Method::Signatures and Method::Signatures in particular. The first MooseX::Method::Signatures, comes bundled as part of MooseX::Declare. MooseX::Declare adds declarative class and method keywords on top of Moose. MooseX::Method::Signatures has it’s own type system and does optional run time type checking on arguments much like you would do with Params::Validate except with a declarative syntax. It’s down right beautiful and makes you warm and fuzzy inside to use it, the down side is there is a huge performance penalty to use MooseX::Method::Signatures at run time. Depending on what you are doing it might not matter much.
The module Method::Signatures gives you 95% of the sugar and 100 x performance over MooseX::Method::Signatures. Type checking at run time is something that I usually don’t need (This is still Perl, I swear). Positional and named parameters are both supported along with defaults and constraints. On my latest project I’ve been using Moose along with Method::Signatures and I couldn’t be any happier. Take a look at the performance benchmarks I’ve included comparing these two modules along with regular ‘sub’ methods.
MooseX::Declare bench code
use MooseX::Declare;
class Foo {
has x => (
is => 'rw',
isa => 'Str',
);
has y => (
is => 'ro',
isa => 'Str',
);
# I use the three vars below to ensure that the subs
# are not constant-folded away. Although I'm not sure perl will do that.
our $meth_counter = 0;
our $meth_without_args_counter = 0;
our $meth_typed_counter = 0;
our $regular_sub_counter = 0;
method method_with_type( Int $x ) {
$meth_typed_counter++;
$self->x . $x
};
method method_without_type($x) {
$meth_counter++;
$self->x . $x
};
method method_without_args() {
$meth_without_args_counter++;
$self->x;
};
sub regular_sub {
my ( $self, $x ) = @_;
$regular_sub_counter++;
$self->x . $x;
}
};
package main;
use Benchmark qw(:all);
my $foo = Foo->new( { x => "3", y => "45" } );
cmpthese(
300000,
{
method_with_type => sub { $foo->method_with_type(5) },
method_without_type => sub { $foo->method_without_type(5) },
method_without_args => sub { $foo->method_without_args() },
regular_sub => sub { $foo->regular_sub(5) },
}
);
MooseX::Declare Results
aaron@ ~/method_signature_bench $ perl MooseXTest.pl
Rate method_without_type method_with_type method_without_args regular_sub
method_without_type 5320/s -- -9% -12% -99%
method_with_type 5865/s 10% -- -2% -99%
method_without_args 6014/s 13% 3% -- -99%
regular_sub 612245/s 11408% 10339% 10080% --
Method::Signatures
package Foo;
use Method::Signatures;
use Moose;
has x => (
is => 'rw',
isa => 'Str',
);
has y => (
is => 'ro',
isa => 'Str',
);
our $meth_counter = 0;
our $meth_without_args_counter = 0;
our $meth_typed_counter = 0;
our $regular_sub_counter = 0;
our $regular_sub_without_args_counter = 0;
method method_without_type($x) {
$meth_counter++;
$self->x . $x
}
method method_without_args() {
$meth_without_args_counter++;
$self->x . '5';
}
sub regular_sub {
my ( $self, $x ) = @_;
$regular_sub_counter++;
$self->x . $x;
}
sub regular_sub_without_args {
my ( $self ) = @_;
$regular_sub_without_args_counter++;
$self->x . '5';
}
package main;
use Benchmark qw(:all);
my $foo = Foo->new( { x => "3", y => "45" } );
cmpthese(
300000,
{
method_without_type => sub { $foo->method_without_type(5) },
method_without_args => sub { $foo->method_without_args() },
regular_sub_without_args => sub { $foo->regular_sub_without_args() },
regular_sub => sub { $foo->regular_sub(5) },
}
);
1;
Method::Signatures Results
aaron@ ~/method_signature_bench $ perl MethodSignature.pl
Rate regular_sub method_without_type regular_sub_without_args method_without_args
regular_sub 579710/s -- -7% -17% -25%
method_without_type 625000/s 8% -- -11% -19%
regular_sub_without_args 701754/s 21% 12% -- -9%
method_without_args 769231/s 33% 23% 10% --
Analysis
These tests are not exhaustive nor do they need to be. Its clear that even with no arguments subs and Method::Signatures are on order of 100 times faster than MooseX::Method::Signatures. What really surprised me here is that Method::Signatures looks to be faster than subs. It would be an interesting test to benchmark the number and types of arguments.
Bottom line is I will use Method::Signatures and Moose in any new projects I write in Perl. I’ve been successfully running production code with Method::Signatures since September with no problems. Hoping to get some feed back on how Method::Signatures could possibly be faster than subs.
Note
- Benchmarks run on a Mac Book Pro with a 2.4ghz core i5 processor and 4b of ram
- Modules tested