Abstract thy SQL
Abstract thy SQL
Let's take a break from Moose. Change gears and visit a topic that I believe every web developer will have to grapple with at some point or another - integrating SQL with a web application. However, the problem is the SQL itself tends to dominate the application. Often times it begins quite innocuously; a developer creates a module that fetches some data from a database and updates it.
Below is an example of a standard insert and select statements using the ubiquitious DBI module:
my $sth = $dbh->prepare("select columny from tablex where id = ?");
$sth->execute(1);
$dbh->do("insert
into tablex (a,b)
values (?,?)", undef ,(1,2) );
We have more than one problem in this example. Not only do we have to manage Perl, but we have to now manage the new embedded DSL known as SQL. As the story unfolds with any code base, what begins as a small application soon grows to thousands of lines of code complicated by various modules that interact with multiple aspects of the database. The once beautiful Perl code base now contains about 40% embedded SQL. The code base becomes fragile and further the database itself is now deeply coupled with the code itself. Because of these two issues it is now difficult to do any upgrades on either the database or the code.
The solution
Now that we have a clear understanding of the problem, how do we go about solving it? First, let's imagine a world where SQL doesn't exist, but all interactions with the database are handled with Perl data structures! Let's dream of a day of when we can create SQL statements without having to write a single bit of SQL. Well, this is a reality and it can be reached with SQL::Abstract.
Here are two simple examples of the same SQL above example, demonstrated using SQL::Abstract.
my ($stmt, @bind) = $sql->select('tablex',
[ 'columny' ],
{ id => 1 });
$sth->prepare($stmt);
$sth->execute(@binds);
my($stmt, @binds) = $sql->insert('tablex', {
a => 1,
b => 2
});
$dbh->do($stmt,undef,@binds);
As mentioned, the advantages of using SQL::Abstract are: no more SQL, cleaner code, and a lower risk of error. SQL::Abstract will generate the needed SQL and the associated bound variables for the place holders - it works seamlessly with any exsting DBI calls.
Wrap up
SQL::Abstract is a well-documented library that will go a long way in improving the quality of maintainable code. However, there are a few shortcomings to SQL::Abstract - it is lightweight and doesn't support many other advanced SQL statements such as "grouping" or "having." However, for the majority of SQL queries, it will work just fine. So have fun and stop polluting the code with embedded SQL!
Roles With Moose
Roles with Moose
In my previous posting I discussed Moose and two advantages to using it. Moose is a large library and it offers so many features that it's difficult to do it justice in a single post. Today, I think it would be good to take a tour of Moose roles. Primarily I would like to describe what they are and how to do some general implementations.
A role you say?
A role in terms of Moose is very similar to a "mix-in" that is common in other languages such as Ruby. The idea behind a role is that it contains methods and attributes that can be applied to a class, but the role itself cannot be initialized like a class. For example, logging is a common usage of role, or anything abstract that adds characteristics to a class. A useful metaphor, as someone once said, is to think of classes as nouns, methods as verbs, and roles as adjectives.
Let's see a a role in action:
package SophisticatedLogger;
use Moose::Role;
sub log {
my ($self, $msg) = @_;
print "$msg\n";
}
Later in our class, we implement or consume the role:
package WebApp;
use Moose;
with 'SophisticatedLogger'; # This consumes the role.
sub do_it {
my $self = shift;
$self->log("We're doing it!");
}
Notice how $self now has access to the "log" method? It gets even better. Let's say that one is privy to the concept of Java interfaces; roles in a similar manner can used to enforce an interface when they are consumed by a class. This means that a role can dictate that a method or attribute be implemented such as in the following example:
package SophisticatedLogger;
use Moose::Role;
requires 'prefix'; # required attribute
requires 'logging_on'; # required method
sub log {
my ($self, $msg) = @_;
print $self->prefix . " - " . $msg . "\n";
}
package WebApp;
use Moose;
has 'logging_on' => ( # must exist before "with" statement
is => 'rw',
isa => 'Int'
);
with 'SophisticatedLogger';
sub prefix { return 'Webapp' }
sub do_it {
my $self = shift;
$self->logging_on(1);
$self->log("We're doing it!");
}
Now if the prefix or logging_on attribute are not defined in the implementing class, this will cause Moose to throw an exception. The only caveat to requiring "attributes" in roles is that it must be defined prior to the "with" statement in the implementing class. However, methods can be defined later in the Moose class.
MODIFYING INSTANCES
Finally, the best part is at run-time we can apply roles to an already initialized object. This is done by importing the Moose::Util function "apply_all_roles".
use Moose::Util qw( apply_all_roles );
my $app = WebApp->new;
apply_all_roles( $app, 'SophisticatedLogger' );
As demonstrated above, this is an extremely powerful feature. This will enable various instances of the same class to have different role flavors. Common use cases could include dynamic configurations that change objects at run-time or for possible debugging efforts on individual objects.
As we can see, roles bring to the table a cleaner way to implement aspect style programming to Perl. It's very exciting to see where Moose is taking Perl.
Modern Perl With Moose
Getting started with Moose
Moose is an object system for Perl. What this means is that it offers a more declarative syntax to make object oriented programming both easier and powerful. Moose incorporates many ideas from the Perl 6 object model and also includes interesting concepts from other languages as well. The two exciting things that Moose offers a developer are more syntactical sugar and the power of introspection.
The old way
Now let's consider the old way of building a class in Perl with a simple getter/setter method.
package Cat;
use base qw(Animal Mammal);
sub is_alive {
my ($self, $bool) = @_;
return $bool ? $self->{is_alive} = $bool : $self->{is_alive};
}
sub new {
my ( $class, %params ) = @_;
my $self = ref $class || $class;
return bless {}, $self;
}
1;
Notice how there is a lot of very perlish idiomatic code that goes into place to make object oriented programming possible. Consider the practices of: "blessing" a hashref, getting $self from the special @_ array, setting $self to a ref of $class, copious amounts of code for a simple setter/getter, and even multiple inheritance! Sheesh, no wonder so many people tend to think of Perl as a haxor script language! However, to Perl's credit (although it depends on one's perspective), the primary reason for some of this eccentricity is due largely to the fact that object oriented Perl was bolted on as an afterthought. It was not part of the core construct of the original language. Thankfully much thought and work has gone into Moose which addresses many of these shortcomings. Let's take a look at two key upgrades that Moose offers - both the sugar and the introspection.
Examples of sugar
As mentioned Moose comes equipped with some syntactic sweetness that makes object oriented programming in Perl a much richer experience. Below is the same code example but using the much cleaner Moose semantics.
package Cat;
use Moose;
extends 'Animal'; # No longer use base
with 'Mammal'; # Introduction of roles
has 'is_alive' => ( # Supports attributes
is => 'rw',
isa => 'Bool'
);
no Moose;
__PACKAGE__->meta->make_immutable;
Notice that Moose supports attributes, roles, and makes inheritance much cleaner.
Examples of introspection
Now one of the most powerful features of Moose is the tools it gives a programmer for introspection. All of this self reflection is brought to Moose by the MOP. Below are a couple examples on how to iterate over class's known methods and attributes.
package Cat;
use Moose;
my $meta = __PACKAGE__->meta;
for my $attr ($meta->get_all_attributes ) {
print $attr->name,"\n";
}
for my $method ( $meta->get_all_methods ) {
print $method->fully_qualified_name, "\n";
}
$meta->add_method( 'meow' => sub { print "meow\n" } );
...
Having this at one's fingertips makes it easier to dynamically create classes, inspect them, add methods, and not feel like one is partaking in any sort of medieval wizardry.
The ability to do this sort of introspection was not possible unless the programmer was confident and comfortable hacking Perl's symbol table. As I mentioned the MOP comes with a whole hosts of powerful meta methods to modify classes and objects at run time.
Where to go from here
Perl is is nearly 25 years old and it's still a very active and rich programming language, as demonstrated in by the vastness of CPAN. The canonical source for more information regarding Moose is the CPAN tutorial or check out the project page. Further, more examples of Moose and how to use it can be found in the official Moose documentation.
So download Moose and start programming with style!
How To Create A Perl Project
How To Create A Perl Project
There are multiple ways to create a Perl CPAN ready module, and one of the most popular ways is to use Module::Starter. In this tutorial we'll walk through how to create a module, write a simple test, write some code, and how to run and test that code.
If one hasn't installed it yet, the following command will take care of this:
$ cpanm Module::Starter
Now that we have Module::Starter installed, it's pretty easy to create the needed directory structure for a CPAN module. This can be done by executing the following command:
$ module-starter -mi -module=HelloWorld -author="Logan Bell" -email=logie@cpan.org
This command will then create the following directory structure:
$ tree HelloWorld
HelloWorld/
├── Changes
├── MANIFEST
├── Makefile.PL
├── README
├── ignore.txt
├── lib
│ └── HelloWorld.pm
└── t
├── 00-load.t
├── boilerplate.t
├── manifest.t
├── pod-coverage.t
└── pod.t
2 directories, 11 files
What's nice about "module-starter" is that it creates all the needed files and boilerplate code, meta-files, and associated tests to deploy a CPAN module.
Now let me give some background on what exactly the various flags represent when we executed the above command. The "mi" flag sets the builder to use Module::Install. Module::Install is a popular module installer. When this package is built it will be built using the constructs that Module::Install uses. The "module" parameter is the name of the Perl Module, in this case HelloWorld, and we have author and email parameters. As obvious as the author and email parameters are, they are needed to populate the various placeholders in the module.
A tip to make life easer in the future, the author and email parameter can be set globally in a config file so that this does not need to be specified each time module-start is run. In order to create a global config for module-start first create a directory in your home path named .module-starter and place a file named "config" with the following key values:
author: Logan Bell
email: logie@cpan.org
Ok, let's take a peek at some of these files shall we? The guts of the program reside in lib/HelloWorld.pm". All of the unit tests for this program live in t/. Further, if we open up the Makefile.PL we'll that it is setup and ready to run with the needed meta information and required modules.
What a Makefile.PL looks like:
use inc::Module::Install;
name 'HellowWord';
all_from 'lib/HelloWord.pm';
author q{Me <logie@cpan.org>};
license 'perl';
build_requires 'Test::More';
requires 'Test::Most' => 0;
auto_install;
WriteAll;
In the Makefile.PL we specify some global parameters that are needed for this module to build.
The "all_from" parameter will extract all the meta data it can from the
source. Further down there is the "build_requires" key, which sets a needed build dependency,
which in this case is Test::Most. The "auto_install" key will install the
needed dependencies and "WriteAll" will create the following files META.yml and the Makefile.
Now let's create a new test by opening "t/001-speak.t". Within this test we'll initialize a HelloWorld and have it utter those infamous words "hello world". Below is some example code:
use Test::Most;
use_ok('HelloWorld');
my $subject = HelloWorld->new;
is $subject->speak, "hello world";
done_testing;
Now on the coding side we'll open lib/HelloWord.pm. The first thing one should see is that there is a fair amount of boiler plate code. Most of this code can be removed, and in fact can be as simple as the following:
package HelloWorld;
use Moo;
=head1 SUBROUTINES/METHODS
=head2 speak
=cut
sub speak {
return "hello world"
}
1;
Now, we can simulate building this package the following way:
$ perl Makefile.Pl
$ make
$ make test
Hopefully if everything is correct we should see the following output:
All tests successful.
Files=6, Tests=8, 0 wallclock secs ( 0.03 usr 0.02 sys + 0.18 cusr 0.03
csys = 0.26 CPU)
Result: PASS
It's really that simple! That's all that is involved in making a CPAN friendly module. Further, all of the source for this project can be found at the following github location.