DBIx::Password is supposed to be a module that:
...provides an abstraction layer for password maintenance. It is
database independent and only overrides the connect method (so it
basically behaves as DBI normally does). You provide a single virtual
user name in the connect method and the module determines which
database/which user/which password to provide.
-- Brian Aker
In this article, I review this module, having used it for 6 months in
a production environment.
Security is an unspoken concern
While not explicitly stated, Brian Aker (module author) has intimated
in personal conversations that a driving design factor of this module
is to keep production database passwords away from people developing
software only for the development environment.
Configuration, not connection
Configuration information is scattered, not centralized
My first issue with this module is that connecting to a database is
application configuration information. Therefore, using this module,
means that application configuration is in at least two places - this
module and one other place for other configuration information.
Kitchen sink: does not catalog database connections - it tries to
make connections also
DBIx::Password tries to make database connections for
you. This is an issue because certain modules,
e.g.
DBIx::AnyDBD, must be supplied connection information not
given a created database handle. I emailed the author patches and he
ignored me. A second email elicited a response about not
wanting an API method for revealing connection information.
layed configuration/inheritance not possible
DBIx::Password does not offer layered configuration
management. There is no way to override some or all of the aspects of
a particular database connection registered with
DBIx::Password.
For a programming module to offer less power in configuration than a
configuration file (which is nothing but a limited programming
language) is hard to understand.
connecting to a database via a string
Here is how you connect to a database using
DBIx::Password
my $dbh = DBIx::Password->connect($user);
theory
A normal DBI connection has 4 options:
- user
- pass
- dsn
- 10 or so possible attributes
What
DBIx::Password does is compress all of this information
down into a single connection string. This can certainly be
convenient, but the practice section will expose the pitfalls of this
for application development.
practice
my $dbh = DBIx::Password->connect($user);
Here are my issues with this:
- there is no easy way to dynamically choose/drop arguments to a DBI
connection. There are at least 10 possible attributes for a DBI
database connection. Since DBIx::Password only accepts a single
string, you are forced to pre-define and compress every desired
combination of 10 attributes into a single string! And then remember
your compression algorithm.
This is similar to the dilemma between using an ORM and writing
SQL. SQL may be more direct, convenient and readable, but when
programmatically generating queries from CGI form data, the high-level
interface to SQL that an ORM provides is valuable.
Concretely. Let's assume that you want
RaiseError on in development and off in production.
Now, if you were being programmatic about this, you would simply have
a hashref of production arguments and a similar hashref of development
arguments (all of which could be over-ridden programmatically at
will):
sub staging_phase {
my($self)=@_;
my %phase = (
'bens.laptop' => 'devel',
'devel.xyz.com' => 'devel',
'webadmin.xyz.com' => 'prod',
'staging.xyz.com' => 'prod' ,
);
my $h = $self->hostname;
my $phase = $ENV{STAGE_PHASE} || $phase{$h} or die 'Could not dete
+rmine stage phase hostname: $h' ;
$self->log->debug( "<staging_phase>$phase</staging_phase>" ) ;
$phase;
}
sub attributes {
$attributes { $self->staging_phase } ;
}
sub connect {
DBI->connect($u, $p, $dsn, $self->attributes);
}
But with DBIx::Password, you would be playing string concatenation
games:
DBIx::Password->connect("${user}_${staging_phase}");
I think it's clear which approach is more scalable, flexible and high-level.
what's the solution?
My initial problems with Brian led to my development of
DBIx::Connect.
The need for layered configuration information led to my development of
Config::DBI.
However, by the time it was all over, a conversation with URI Guttman about
application configuration convinced me that a Perl module/class is the most
flexible and powerful solution for application configuration.
The use of programming objects for powerful configuration is supported
by this python
whitepaper
as well.
I
echoed his sentiments
during my Python days as well.