Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Intelligent Package Interaction

by nmerriweather (Friar)
on Nov 21, 2004 at 18:12 UTC ( [id://409390]=perlquestion: print w/replies, xml ) Need Help??

nmerriweather has asked for the wisdom of the Perl Monks concerning the following question:

A few months ago, I posted a question on passing DB handles through functions and packages here that related to a similar question here

I've realized that this could be better addressed by some sort of intelligent interaction by packages -- one that I can't figure out. Hopefully someone here can help.

I've created a base framework of packages for webapplications under mod_perl that contain functions I often use.

MyFramework
MyFramework::DBIClass
MyFramework::UserClass
MyFramework::FormClass

What I then do, is make another set of packages subclassing the first.

MyWebApp
MyWebApp::DBIClass (isa MyFramework::DBIClass)
MyWebApp::UserClass (isa MyFramework::UserClass)
MyWebApp:: FormClass (isa MyFramework::FormClass)

Here lies the problem:
Everything works GREAT when I pass around lots of info -- like references to the DB configuration. I'm trying to limit all passing around of arguments though -- and need to figure out some way to get all of the various MyFramework packages to access the configuration for MyWebApp::DBI or MyWebApp::Configuration . In the preceding example, I created a webapp called 'MyWebApp' -- though it could also be called 'MyWebApp2' or something similar to better illustrate the problem.

Can anyone suggest some ways in which I can structure this system so that I can limit the references passed around, and have the packages intelligently make queries for the correct info.

2004-11-21 Janitored by Arunbear - fixed links to previous questions

Replies are listed 'Best First'.
Re: Intelligent Package Interaction
by saberworks (Curate) on Nov 21, 2004 at 21:59 UTC
    I would recommend storing the important things like database handles in a package variable of your parent class. In there, just use our $dbh; and then populate $dbh in the constructor. Then any sub can just use that directly, without having to get it from @_ or querying with a CGI.pm-esque param() function.
Re: Intelligent Package Interaction
by nothingmuch (Priest) on Nov 22, 2004 at 07:29 UTC
    In my current project I the ideas from the other replies a bit further.

    The configuration is active, the code caring about the configuration is stupid (well, the part that asks about configuration, anyway). Here is how it's done:

    I have a namespace, MyApp::Config. MyApp::Config::Env provides environment probing data (MyApp::Config::Env->under_test will look at $0 to see if it matches /t/.+\.t$/, or $ENV{HARNESS_ACTIVE}), for the other modules.

    Then, each module on it's own uses the Env module to provide configuration.

    For example, the MyApp::Config::DBI will, under test, select PostgreSQL or MySQL, depending on which is on right now. This is done by instantiating little objects that score themselves, and having a singleton class whose constructor will simply select the best scoring one of these.

    Under production, the One True Database is chosen, and otherwise an error is generated.

    This functionlity is important, IMHO, to make the app work well, but it doesn't belong in the Real Code. Given global variables, the flexibility is limited, though.

    I do it by using class methods - Config::DBI->dbh delegates to the object that was chosen, asking it to make a new database handle.

    This goes further though, I also have configurating objects. For example, I have a class which runs a command line program. It cares about the interaction with the program, but not the program itself. This program has some variations, depending on the input data, the environment, and so forth. The configurator objects uses MyApp::Config::Env to see what the command should be, and then when MyApp::Config::ThatProgram->configure($obj) is called, the $obj, which is responsible for posessing the app, is modified to suite the environment.

    Separating configuration from logic has made my app pretty maintainable so far, with a lot of space to grow.

    Basically, what I suggest is to stop passing around data, and make a central point to get configuration data from. If there are complexities with who gets what, then that central point should be smart to resolve these differences, and real code shouldn't care.

    You don't lose any flexibility, but what you gain is simplicity of the important code. This comes at a cost - the configuration code might be leaning towards magic, or become complex, but usually this code is quite linear to write, and the clarity of the real logic is, IMHO, well worth it.

    Ciao!

    -nuffin
    zz zZ Z Z #!perl
      Wow - serendipity. I'm in a similar situation, just starting to get my mind around this same problem - having the module/app "know" which backend is up.

      Any chance I could take a peek at your solution? The idea of "little objects that score themselves" intrigues me...

Re: Intelligent Package Interaction
by simonm (Vicar) on Nov 21, 2004 at 21:50 UTC
    Create a well known place where you will store references to the active classes and objects; this can be a package variable, singleton objects, a registry or whatever.

    Here's a sketch using a package variable:

    package MyFramework::DBIClass; sub setup { $MyFramework::ActiveDBIClass->connect_database } ... package MyWebApp; $MyFramework::ActiveDBIClass = 'MyWebApp::DBIClass';
Re: Intelligent Package Interaction
by nmerriweather (Friar) on Nov 22, 2004 at 00:37 UTC
    Thank you all. Will experiment immediately!
Re: Intelligent Package Interaction
by eclark (Scribe) on Nov 22, 2004 at 21:08 UTC
    I recently saw something on CPAN that I really liked, an Inversion of Control framework. I havent tried IOC yet, but the idea is sound.
      Oooh, that's really cool.

      /me puts on his miner's helmet and prepares to dig...

Re: Intelligent Package Interaction
by Anonymous Monk on Nov 22, 2004 at 21:00 UTC
    I do things via a common package with accessor functions. Something like this.
    use NYSCUL::ConfAssist qw(getDbConn loadConfig); loadConfig("myconf.xml"); foo(); sub foo { my($db)=getDbConn("mydb"); . . . }
    It works fairly well for me. "getDbConn" consults the programs config info to get all the info it needs and off I go.
Re: Intelligent Package Interaction
by Anonymous Monk on Nov 22, 2004 at 22:07 UTC

    I've since stopped passing information around, and now call out to a specific module for the config information

    This isn't working out too well though.

    I still don't understand how to set things up (or even its its possible) to have the following

    MyFramework MyApp1::Config MyApp2::Config

    And have MyFramework::Namespace call out the correct MyApp1::Config or MyApp2::Config

      Here are the key elements:
      • The code in MyFramework must always refer to a variable (or other registry mechanism) to find the name or reference to use.
      • At startup time (if each process only loads one application) or at the start of each request (if a persistent interpreter serves multiple applications), load the appropriate MyApp modules and store their names or references in the variables/registry.

      It sounds like you've got the first but not the second.

        This will likely sound silly -- but could this be approximated by specifying the configuration info in UNIVERSAL, and having apps look to it in there?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://409390]
Approved by Zaxo
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (3)
As of 2024-04-24 15:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found