Getting big without getting fat, in perl

6 min read Original article ↗
  • 1.
  • 2.
  • 3.

    Whipupitude and Getting ThingsDone! ● Whipupitude is a Perl strength ○ Great at getting from 0 to 1 ● Quick perl scripts tend to become enterprise software (possibly better written?) ● Getting Things Done > Unfinished ‘Better’ ○ A business making money from in-production code is a business with the luxury of rewriting in- production code! ○ The quality (hence cost) of the solution needs to match the problem being solved ○ (We are artists, so trade offs don’t always sit well)

  • 4.

    Going from 1to 1+ ● Initially we had nothing, now we have something ● It works well enough that now we have the luxury of rewriting it ● “I was right” attitudes forget that we had to get from 0 to 1 :) ● As our business/platform is now making money, its a “problem” that demands a better solution

  • 5.
  • 6.

    Make the paingo away ● Structuring your code to add features easily & quickly ● Ensure that existing features keep working and new features work as planned ● Providing the right buttons and knobs to make life easier for humans

  • 7.
  • 8.
  • 9.

    Logging. See my talkfrom last month. tl;dr? ● Try Log::Log4perl ● Try Log::Dispatch ● Profit!

  • 10.
  • 11.

    Plugins 101 ● Easilyadd functionality ● Easily remove functionality ○ Make things ‘pluggable’! ● Simplify parallel development ● Facilitate orthogonal requirements/needs ● Loose coupling and separation of concerns ● Simplify testing!

  • 12.

    Dog Food Philosophy ●State your API publically ● Move all functionality into plugins, use only your stated API ● Keep only basic functionality in the core of the application ● Ideally, the core should rarely change By using your own API you will quickly discover it’s weaknesses!

  • 13.

    Measurements of success ●Separation of concerns achieved (I have no idea how you measure this?) ● You can change the internals without changing the plugins! ● Others can make a plugin without understanding all (or any!) internals ● It’s so easy (and fun!) to write plugins that people are doing it whimsically

  • 14.
  • 15.
  • 16.

    Hooks ● The pluginregisters with the program ○ “I can read image/png files” ○ “Tell me when the user enters a URL” ○ “Call me when a new connection is opened” ● Fine grained control ● Helps provide a clear API ● Can be a pain to put in hook calls everywhere it’s (possibly) needed

  • 17.

    Hooks as overrides:Net:: Server In Net::Server you override the default hook handlers (which do nothing). The basic flow is shown below: $self->configure_hook; # Hook $self->configure(@_); $self->post_configure; $self->post_configure_hook; $self->pre_bind; $self->bind; $self->post_bind_hook; $self->post_bind; $self->pre_loop_hook; $self->loop; # lots of others inside $self->loop $self->pre_server_close_hook; $self->server_close; Others (not in ->loop): $self->can_read_hook() $self->allow_deny_hook() $self->request_denied_hook() $self->post_process_request_hook() $self->post_client_connection_hook() $self->other_child_died_hook($pid) $self->write_to_log_hook() $self->fatal_hook() $self->post_child_cleanup_hook() $self->restart_open_hook() $self->restart_close_hook() $self->child_init_hook() $self->pre_fork_hook() $self->child_finish_hook()

  • 18.

    E.g. Net::Server (cont.) usestrict; use warnings; package My::Thing; use parent qw( Net::Server::PreFork ); # pick your personality sub _rename_me { $0 = q|Me: | . $_[0] } sub post_bind_hook { _rename_me(q/listening/) } sub process_request { _rename_me(q/running/); do_stuff() } package main; My::Thing->run(port => 12345);

  • 19.

    The overrides way: ●Uses normal perl inheritance ● In Net::Server you can override stuff that’s not intended as a hook for full blown perl madness ● AUTOLOAD can be a lot of fun here ● Only allows one sub to be called on each hook, although your sub could call SUPER::

  • 20.

    Class::Trigger ● Allows yourmain program to define hooks (triggers) and when they are called ● Provides methods so that your plugin attaches it’s subs to these hook points ● Triggers can optionally have callbacks! ● Triggers are inherited! ● Triggers are called in the same order they are attached

  • 21.

    Delegation The program tellsthe plugin/extension/module: You go take care of this stuff ● “you take care of the database connection” ● “you parse the XML” Not so good for small tweaks and add-ons Inheritance is / can be a variation of this

  • 22.

    Roles ● Are whena package (class) is required to implement certain sub’s (methods) ● DIY with sub foo { die ‘missing foo’ } in your base class (don’t though) ● Use Role::Tony, Moo::Role or similar ● Both complain early and loud that things are missing ● Plus other helpful stuff

  • 23.

    Mix-ins ● Add methodsinto existing base classes ● Good for adding new stuff to frameworks ● Not so good for changing how something works ● Usually not good for application plugins The Catalyst framework uses this method, which is how methods magically appear on $c

  • 24.

    Flat-file vs Modules Flat-file ●OK for simple stuff ● You’ll have to locate and load them ● Namespace dramas ● Crude entry/exit points Modules ● Full-access to Perl OO goodness ● Perl can take care of locating them ● Elegant touch points

  • 25.

    Flat File &.pm compared cat Plugins/Example.pl #!perl use strict; use warnings; sub _hello { print qq|hello!n| } # just one action, final statement sub { _hello() } cat Plugins/Example.pm #!perl use strict; use warnings; package App::Plugins::Example; our $VERSION = 0.1; sub _hello { print qq|hello!n| } sub action1 { hello() } sub action2 { print qq|bai!n| } 1

  • 26.
  • 27.

    Use Module::Pluggable #!perl package MyClass; useModule::Pluggable; use MyClass; my $mc = MyClass->new(); # returns the names of all plugins installed under MyClass::Plugin::* my @plugins = $mc->plugins(); # Or if you want to look in another namespace use Module::Pluggable search_path => ['Acme::MyClass::Plugin', 'MyClass:: Extend']; # You can limit the plugins loaded using the except option, either as a string, array ref or regex use Module::Pluggable except => 'MyClass::Plugin::Foo'; # Or if you want to instantiate each plugin rather than just return the name use Module::Pluggable instantiate => 'new'; # Alternatively you can just require the module without instantiating it use Module::Pluggable require => 1;

  • 28.

    M::P::Object for OO #!perl packageMyClass; use Module::Pluggable::Object; my $finder = Module::Pluggable::Object->new(%opts); print "My plugins are: ".join(", ", $finder->plugins)." n"; Other options as per Module::Pluggable. There are so so many :)

  • 29.
  • 30.

    Config (CLI) ● GetOpt::Long Doesit need introducing? I am open to alternatives though... ● Pod::Usage Prints a usage message from embedded pod documentation (do things once!)

  • 31.

    Config (file) “Config::Any providesa facility for Perl applications and libraries to load configuration data from multiple different file formats. It supports XML, YAML, JSON, Apache-style configuration, Windows INI files, and even Perl code.”

  • 32.

    Config (file) (cont.) ●Config::General deserves an extra look ● Apache style config files ● Lots of control over how the config is interpreted and processed for you: ○ (Dis)allow multiple identical options? ○ Lower case all names? ○ Include directories, globs? over and over? ○ Merge duplicates? ○ Taint cleaning ○ Conversion to boolean (“true” and “false”) ○ Much much more!

  • 33.

    Config (file) (cont.) Fragmentingconfig files is really good idea. We know this because Debian does it religiously: What Would Debian Do? /etc/whatever/conf.d/*conf Facilitates separation of concerns, works well with plugins Makes writing helper scripts super easy

  • 34.

    Just email meor find me on Facebook Dear Internet, Please contact me and tell me where I can do better! I don’t (yet) know everything

  • 35.
  • 36.

    Other good stuff: ●Writing Pluggable Software http://www.slideshare.net/miyagawa/writing-pluggable-software ● Build Easily Extensible Perl Programs http://www.askbjoernhansen.com/archives/2005/08/Build_Easily_Extensible_Perl_Programs.pdf