0
Exporter::Proxy



Splitting up modules to help your sanity.


          Steven Lembark
        Workhorse Computing
Stuck in Lodi Again
●   We've all been there: the 4000­line module.
●   It began small enough... then it grew.
●   Canned­...
Welcome to the Machine
●   You have to clean up the module.
●   You need to split the thing into usable chunks.
    ●   Se...
This is Perl, however.
●   So you will practice True Lazyness (c). 
●   This means doing it once.
●   Doing it right.
●   ...
Lazyness is a virtue
●   Exporting in Perl should be easy, but Exporter is 
    complicated (and error prone).
●   Breakin...
Un­lazy Shared Variables.
●   Exporter allows sharing variables.
●   If you inherit from it.
●   If you keep proper track ...
False Lazyness:
●   Break the module up by function,  the names don't 
    immediately collide: Lookup::userid,  Modify::u...
Un­Lazy Top­Half Modules
●   Another way to split up the modules is a single God 
    Object dispatcher that “figures out”...
Exporter::Proxy
●   This is Perl, there is a lazy way.
●   E::P simplifies you work by:
    ●   Exporting symbols.
    ●  ...
“The simplest interface is none at all”
●   Instead of having to define a set of variables for your 
    set of variables,...
Lazy Dispatcher
●   These look pretty much the same: decide where the 
    call goes, send it there, and get out of the wa...
Splitting Up The Interface
●   You've probably witnessed *NIX device drivers .
●   The top half validates and dispatches t...
Breaking Up A Module
●   You can usually break the combined interface up 
    into functional groups:
    ●   “modify” vs....
Looking At A Query Module
●   “modify” and “lookup” are probably good divisions.
●   The SQL for canned queries is probabl...
Bottom Half Does the Work.
●   The bottom half implements methods for specific 
    tasks and exports a single dispatcher ...
The Public Interface is Truly Lazy
●   Bottom halves export their dispatchers: just collect 
    them together into a sing...
What the Caller Sees
●   Anyone using “Query” just knows that its API 
    includes “lookup”, “modify”, and “verbose”.
●  ...
Lazy Growth
●   Re­factoring the interface into subject areas is also 
    straightforward:
    ●   Add new modules “depar...
Summary
●   True Lazyness is a virtue.
●   Dispatching interfaces offer a simple way to 
    segregate the classes.
●   To...
Upcoming SlideShare
Loading in...5
×

Exporter Proxy

501

Published on

This helps break up bloated modules -- or keeping new ones manageable -- by simplifying variable and method export and adding package-space dispatchers to modules. The talk uses the example of an overgrown Query module.

Published in: Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
501
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
1
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Exporter Proxy"

  1. 1. Exporter::Proxy Splitting up modules to help your sanity. Steven Lembark Workhorse Computing
  2. 2. Stuck in Lodi Again ● We've all been there: the 4000­line module. ● It began small enough... then it grew. ● Canned­query modules are classics for this: ● In the beginning was “userid”, and it was good, enough. ● Then it was split into get_userid/set_userid. ● Then it branched into get_dept_userid,  get_general_userid and set_*.  ● That was then, your cleanup is now.
  3. 3. Welcome to the Machine ● You have to clean up the module. ● You need to split the thing into usable chunks. ● Separating out namespaces. ● Keeping shared variables in a reasonable place. ● Keeping utility subs out of the way. ● By tomorrow. In parallel universes, in constant time.
  4. 4. This is Perl, however. ● So you will practice True Lazyness (c).  ● This means doing it once. ● Doing it right. ● And never having to do it again.
  5. 5. Lazyness is a virtue ● Exporting in Perl should be easy, but Exporter is  complicated (and error prone). ● Breaking up large modules into manageable chunks  often takes too much work. ● Both of these should be easy.
  6. 6. Un­lazy Shared Variables. ● Exporter allows sharing variables. ● If you inherit from it. ● If you keep proper track of EXPORT_OK,  EXPORT, EXPORT_TAGS. ● If, hopefully, @foo never changes to %foo. ● There has to be a better way...
  7. 7. False Lazyness: ● Break the module up by function,  the names don't  immediately collide: Lookup::userid,  Modify::userid ● But, you can't inherit both classes without collisions. ● You could try Lookup::Dept::userid and  Modify::Dept::userid. ● But do you really want to see: $qryobj->Lookup::Dept::userid( ... ); Let alone type it?
  8. 8. Un­Lazy Top­Half Modules ● Another way to split up the modules is a single God  Object dispatcher that “figures out” how to dispatch  into the various pieces of the original module.  ● This ends up being either a un­maintainable if­ block, an un­readable n­ary ternary op, or the  Switch From Hell (tm). ● The problem is that the caller knows what they  want: expose them to the decisions and let them  make the proper one.
  9. 9. Exporter::Proxy ● This is Perl, there is a lazy way. ● E::P simplifies you work by: ● Exporting symbols. ● Installing an import sub to export the symbols. ● Optionally installing a dispatch sub. ● This allows you to split your modules into layers: ● A top­half dispatcher that combines the moduels. ● The bottom­half modules that actually do the work. ● Common shared variables, all stored in one place.
  10. 10. “The simplest interface is none at all” ● Instead of having to define a set of variables for your  set of variables, just: use Exporter::Proxy qw( verbose debug foobar ); ● Whatever names you provide are exported as  symbols via Symbol: my $source = qualify_to_ref $_, $source; my $install = qualify_to_ref $_, $caller; *$install = *$source; ● $verbose, &verbose, @verbose, %verbose, all you  have to export is “verbose”.
  11. 11. Lazy Dispatcher ● These look pretty much the same: decide where the  call goes, send it there, and get out of the way. ● This is done in Exporter::Proxy with the “dispatch=”  argument. ● The dispatcher is exported by default. ● Each one dispatches calls within its own package: my $name = splice @_, 1, 1; my $dest = $package->can( $name ) or croak “$package cannot '$name'”; goto &$dest;
  12. 12. Splitting Up The Interface ● You've probably witnessed *NIX device drivers . ● The top half validates and dispatches the call, the  bottom half just does things. ● The top half doesn't care what does on, it just sends  things where they belong. ● The bottom half doesn't care why it does things, it  just does them.
  13. 13. Breaking Up A Module ● You can usually break the combined interface up  into functional groups: ● “modify” vs. “lookup” ● “department” vs. “office” vs. “location”. ● “Taxid”, “GenBank”, “Medline”, “MeSH”. ● You can also combine any shared variables into a  single module that exports them as needed.
  14. 14. Looking At A Query Module ● “modify” and “lookup” are probably good divisions. ● The SQL for canned queries is probably sharable.  ● The query methods don't care who their caller is. ● The dispatcher doesn't care why the methods were  called, it just has to hand back the data. ● Code something like: $query->lookup( department => @argz ); $query->modify( department => @argz ); ● Is reasonably mnemonic and easily extended.
  15. 15. Bottom Half Does the Work. ● The bottom half implements methods for specific  tasks and exports a single dispatcher for them. ● Break the module up into Query::Lookup,  Query::Modify, Query::Shared. ● Lookup & Modify install a dispatcher: use Exporter::Proxy qw( dispatch=lookup ); use Exporter::Proxy qw( dispatch=query ); ● They pull in shared content by Using Query::Shared: package Query::Modify; use Query::Shared qw( modify_dml ); # SQL hash
  16. 16. The Public Interface is Truly Lazy ● Bottom halves export their dispatchers: just collect  them together into a single API. package Query; use Query::Lookup; use Query::Modify; use Query::Shared qw( verbose ); sub verbose { @_ ? $verbose = shift : $verbose } 42 __END__ ● The Top Half is DUMB: there are no decisions here,  no special cases, no edge cases.
  17. 17. What the Caller Sees ● Anyone using “Query” just knows that its API  includes “lookup”, “modify”, and “verbose”. ● The methods take a first argument of what to lookup  or modify, and whatever arguments it needs. ● They don't have to know about the bottom­half,  shared variables, or utility sub's that aren't exported  by the bottom­half modules into the API. ● This is what makes the Top Half dumb: the caller  makes their own decisions on what to call.
  18. 18. Lazy Growth ● Re­factoring the interface into subject areas is also  straightforward: ● Add new modules “department”, “office”, “frobnicate”. ● Each has a mnemonic dispatcher, say, “dept”, “office”,  and “frob”. ● They implement whatever methods describe the action. ● They can share the existing SQL or define their own. ● The caller uses, say, $query->dept( id => $dept_name );
  19. 19. Summary ● True Lazyness is a virtue. ● Dispatching interfaces offer a simple way to  segregate the classes. ● Top­half classes can implement mnemonic API's. ● Bottom duty can be bearable with Exporter::Proxy.
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×