Alias's Journal http://use.perl.org/~Alias/journal/ Alias's use Perl Journal en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-01-25T01:44:58+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 Alias's Journal http://use.perl.org/images/topics/useperl.gif http://use.perl.org/~Alias/journal/ DBD::SQLite 1.31 releasing next week and may break your code http://use.perl.org/~Alias/journal/40526?from=rss <p>After 6 or 7 months (mainly waiting around for the next "recommended upgrade instruction" from the SQLite project) the latest DBD::SQLite release should occur next week.</p><p>You can get the 1.30_06 release candidate from the CPAN, or from the following URL if your mirror hasn't synced yet.</p><p><a href="http://svn.ali.as/cpan/releases/DBD-SQLite-1.30_06.tar.gz">http://svn.ali.as/cpan/releases/DBD-SQLite-1.30_06.tar.gz</a></p><p>Apart from the normal batch of SQLite upgrades (from 3.6.22 to 3.7.2), bug fixes, and minor enhancements, this release has two changes that may break your code.</p><p>These changes have been in the dev releases for some time, but you may want to take the opportunity to test more intensively if you use either of the following features.</p><p>1. BLOB columns with UTF8 content</p><blockquote><div><p> <tt>- Resolved #54271: Inserting a string with utf-8 flag on<br>&nbsp; corrupts BLOB data; now BLOB data is always stored as bytes<br> &nbsp; (without the utf-8 flag) even if it has the flag set (ISHIGAKI)</tt></p></div> </blockquote><p>2. FTS3 queries</p><blockquote><div><p> <tt>- Added support for FTS3 tokenizers written in Perl. Added tests<br>&nbsp; and documentation on how to use FTS3. Changed compilation flag<br>&nbsp; to use the recommanded -DSQLITE_ENABLE_FTS3_PARENTHESIS<br>&nbsp; *** MAY POSSIBLY BREAK OLD APPLICATIONS THAT ALREADY USED FTS3 ***<br>&nbsp; (DAMI)</tt></p></div> </blockquote><p>If you are currently using FTS3, please see <a href="http://search.cpan.org/perldoc?DBD::SQLite::FTS3Transitional">DBD::SQLite::FTS3Transitional</a> which contains a helper function for automatically upgrading old FTS3 queries to the new syntax.</p> Alias 2010-09-09T02:11:54+00:00 journal Should Module::Install move to explicit plugin declaration? http://use.perl.org/~Alias/journal/40523?from=rss <p>Module::Install has been through a long period of gradual stability over the last year, without any really dramatic improvements to the grammar or APIs.</p><p>With the more urgent "it doesn't work with blah" stuff mostly solved now, one of the big remaining issues is around error clarity and excessive magic.</p><p>For example, some random author that is trying to checkout a Catalyst project needs:</p><p>1. To have Module::Install installed.<br>2. To have Module::Install::Catalyst installed.</p><p>In the case of the former, you get the semi-cryptic but at least standard "Can't find inc/Module/Install.pm in @INC" message, so the error is resolvable.</p><p>But in the latter case, you're likely to get something like "Unknown command 'catalyst_ignore'", with no real obvious resolution mechanism.</p><p>I think this idea of automatic plugin discovery is starting to hit it's limits in terms of clarity.</p><p>And so I'd like to do something counter to my natural instincts here, and make M:I more verbose.</p><p>I'm thinking of something like the following for explicitly declaring the use of a non-core Module::Install extension.</p><blockquote><div><p> <tt>use inc::Module::Install qw{ Catalyst XSUtil };</tt></p></div> </blockquote><p>This would both allow M:I to error with a much more meaningful error when you don't have a plugin, and also prevent the loading of unused plugins which should prevent accidental plugin collisions (some of which I've seen occurring in the CPAN Testers machines).</p><p>Thoughts?</p> Alias 2010-09-06T02:26:06+00:00 journal Speaking at Microsoft TechEd - Any issues you want raised? http://use.perl.org/~Alias/journal/40508?from=rss <p>Next week I will at Microsoft's TechEd Australia event, courtesy of Microsoft Australia and Microsoft Open Source Labs.</p><p>More specifically, I'll be attending the Open Source mini-conf and discussion day on Tuesday, and presenting in the Community Presentations to Microsoft session on the current state of Perl and Windows on Wednesday.</p><p>Likely topics will include a review of the first year of the CPAN Testing Lab and a second-generation based on their Cloud Services, free code signing certificates for open source developers, and what issues are slowing us down or blocking progress.</p><p>So consider this your opportunity to raise any outstanding issues you have with Microsoft and Perl. What problems are you still seeing, what would like fixed or changed, and what is on your want-to-have list?</p><p>I'll try to address as many of your issues as possible in the time I have available with them (which is actually pretty substantial).</p> Alias 2010-08-20T03:20:46+00:00 journal Class::XSAccessor now even faster'er http://use.perl.org/~Alias/journal/40497?from=rss <p>The new 1.07 release of <a href="http://search.cpan.org/perldoc?Class::XSAccessor">Class::XSAccessor</a> mentions the use a new somewhat-evil technique for making the code even faster than it was previously.</p><p>But how much faster is it?</p><p>The following are being run on a fairly typical corporate Windows XP machine, with Strawberry Perl 5.10.1 and thread support.</p><p>First, some benchmarks using the previous 1.05 release (two runs)</p><blockquote><div><p> <tt>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 1 wallclock secs ( 2.51 usr +&nbsp; 0.00 sys =&nbsp; 2.51 CPU) @ 3976143.14/s (n=10000000)<br>accessor_set:&nbsp; 2 wallclock secs ( 3.09 usr +&nbsp; 0.00 sys =&nbsp; 3.09 CPU) @ 3233107.02/s (n=10000000)<br>constructor: 16 wallclock secs (15.67 usr +&nbsp; 0.00 sys = 15.67 CPU) @ 638080.65/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 2 wallclock secs ( 1.91 usr +&nbsp; 0.00 sys =&nbsp; 1.91 CPU) @ 5243838.49/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 1 wallclock secs ( 2.34 usr +&nbsp; 0.00 sys =&nbsp; 2.34 CPU) @ 4266211.60/s (n=10000000)<br> &nbsp; predicate:&nbsp; 1 wallclock secs ( 2.38 usr +&nbsp; 0.00 sys =&nbsp; 2.38 CPU) @ 4210526.32/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 2 wallclock secs ( 3.27 usr +&nbsp; 0.00 sys =&nbsp; 3.27 CPU) @ 3061849.36/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 1 wallclock secs ( 1.80 usr +&nbsp; 0.00 sys =&nbsp; 1.80 CPU) @ 5564830.27/s (n=10000000)<br> &nbsp; <br>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 3 wallclock secs ( 2.51 usr +&nbsp; 0.00 sys =&nbsp; 2.51 CPU) @ 3976143.14/s (n=10000000)<br>accessor_set:&nbsp; 3 wallclock secs ( 3.14 usr +&nbsp; 0.00 sys =&nbsp; 3.14 CPU) @ 3183699.46/s (n=10000000)<br>constructor: 15 wallclock secs (15.73 usr +&nbsp; 0.00 sys = 15.73 CPU) @ 635566.29/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 2 wallclock secs ( 1.86 usr +&nbsp; 0.00 sys =&nbsp; 1.86 CPU) @ 5379236.15/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 3 wallclock secs ( 2.50 usr +&nbsp; 0.00 sys =&nbsp; 2.50 CPU) @ 4000000.00/s (n=10000000)<br> &nbsp; predicate:&nbsp; 3 wallclock secs ( 2.47 usr +&nbsp; 0.00 sys =&nbsp; 2.47 CPU) @ 4050222.76/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 4 wallclock secs ( 3.13 usr +&nbsp; 0.00 sys =&nbsp; 3.13 CPU) @ 3200000.00/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 2 wallclock secs ( 1.98 usr +&nbsp; 0.00 sys =&nbsp; 1.98 CPU) @ 5037783.38/s (n=10000000)</tt></p></div> </blockquote><p>And now again with the new 1.07 release.</p><blockquote><div><p> <tt>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 2 wallclock secs ( 1.75 usr +&nbsp; 0.00 sys =&nbsp; 1.75 CPU) @ 5711022.27/s (n=10000000)<br>accessor_set:&nbsp; 1 wallclock secs ( 2.69 usr +&nbsp; 0.00 sys =&nbsp; 2.69 CPU) @ 3721622.63/s (n=10000000)<br>constructor: 15 wallclock secs (15.62 usr +&nbsp; 0.00 sys = 15.62 CPU) @ 640000.00/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 1 wallclock secs ( 1.28 usr +&nbsp; 0.00 sys =&nbsp; 1.28 CPU) @ 7806401.25/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 1 wallclock secs ( 1.56 usr +&nbsp; 0.00 sys =&nbsp; 1.56 CPU) @ 6397952.66/s (n=10000000)<br> &nbsp; predicate:&nbsp; 2 wallclock secs ( 1.92 usr +&nbsp; 0.00 sys =&nbsp; 1.92 CPU) @ 5205622.07/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 3 wallclock secs ( 2.50 usr +&nbsp; 0.00 sys =&nbsp; 2.50 CPU) @ 4000000.00/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 2 wallclock secs ( 1.55 usr +&nbsp; 0.00 sys =&nbsp; 1.55 CPU) @ 6464124.11/s (n=10000000)<br> &nbsp; <br>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 2 wallclock secs ( 1.78 usr +&nbsp; 0.00 sys =&nbsp; 1.78 CPU) @ 5614823.13/s (n=10000000)<br>accessor_set:&nbsp; 3 wallclock secs ( 2.63 usr +&nbsp; 0.00 sys =&nbsp; 2.63 CPU) @ 3809523.81/s (n=10000000)<br>constructor: 16 wallclock secs (15.69 usr +&nbsp; 0.00 sys = 15.69 CPU) @ 637429.88/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 2 wallclock secs ( 1.22 usr +&nbsp; 0.00 sys =&nbsp; 1.22 CPU) @ 8203445.45/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 2 wallclock secs ( 1.53 usr +&nbsp; 0.00 sys =&nbsp; 1.53 CPU) @ 6535947.71/s (n=10000000)<br> &nbsp; predicate:&nbsp; 2 wallclock secs ( 1.78 usr +&nbsp; 0.00 sys =&nbsp; 1.78 CPU) @ 5614823.13/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 2 wallclock secs ( 2.56 usr +&nbsp; 0.00 sys =&nbsp; 2.56 CPU) @ 3903200.62/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 2 wallclock secs ( 1.48 usr +&nbsp; 0.00 sys =&nbsp; 1.48 CPU) @ 6738544.47/s (n=10000000)</tt></p></div> </blockquote><p>The numbers are pretty impressive.</p><p>The 'accessor', 'setter', 'predicate' and 'true' methods are about 25% faster, while 'getter' is a whopping 60% faster and (curiously) 'false' is about 50% faster as well.</p><p>Constructors are really the only thing that hasn't changed.</p><p>Impressive work, even if the code is a bit risky.</p> Alias 2010-08-16T03:04:05+00:00 journal Why does Object::Tiny only support getters http://use.perl.org/~Alias/journal/40496?from=rss <p><a href="http://perlalchemy.blogspot.com/2010/08/objecttinyrw-and-moosexnonmoose.html">http://perlalchemy.blogspot.com/2010/08/objecttinyrw-and-moosexnonmoose.html</a></p><p>Zbigniew Lukasiak tries out <a href="http://search.cpan.org/peldoc?Object::Tiny">Object::Tiny</a> and wonders why it is that I didn't allow for the creation of setters when it is only a one line change.</p><p>Like most<nobr> <wbr></nobr>::Tiny modules the reason is a bit complex and the result of compromises.</p><p>Object::Tiny began as an attempt to create a lighter, faster, version of Class::Accessor. A way to bulk-generate the accessor code I had to type over and over again.</p><p>However, where I differ is a strong preference for light and elegant API design.</p><p>And so I decided to implement mine with as little implementation code as possible, and as little API code as possible.</p><p>Once you have decided to go down the simplicity path, there's a couple of standard techniques you often end up using.</p><p>The first and most important is state reduction.</p><p>In their introduction to Erlang, the founders of that language describe state as one of the main sources of failures in programs. And so anything that removes state, at the very least unnecessary state, is a positive. Especially if the state reduction also results in code reduction, and a reduction in computation.</p><p>So take the following example, where we create an object with some attributes and then run some code that will use those object attributes..</p><blockquote><div><p> <tt>my $object = Class-&gt;new;<br>$object-&gt;foo(1);<br>$object-&gt;bar(2);<br>$object-&gt;do_something;</tt></p></div> </blockquote><p>This is a use case that we see fairly often, but it's really quite horrible code. It is really only the object-oriented equivalent of something like the following.</p><blockquote><div><p> <tt>our $Object::foo = 1;<br>our $Object::bar = 2;<br>do_something('Object');</tt></p></div> </blockquote><p>It is especially bad code if the following code would throw an exception.</p><blockquote><div><p> <tt>my $object = Class-&gt;new;<br>$object-&gt;do_something;</tt></p></div> </blockquote><p>If this blows up, then you are REALLY doing something wrong, because you have allowed the creation of completely invalid objects. Now anybody taking one of these objects as a parameters needs to do with following.</p><blockquote><div><p> <tt>sub foo {<br>&nbsp; &nbsp; my $object = shift;<br>&nbsp; &nbsp; unless (<br>&nbsp; &nbsp; &nbsp; &nbsp; $object-&gt;isa('Class')<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; defined $object-&gt;foo<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; $object-&gt;foo &gt; 0<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; defined $object-&gt;bar<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; $object-&gt;bar &gt; 2<br>&nbsp; &nbsp; ) {<br>&nbsp; &nbsp; &nbsp; &nbsp; die "Invalid object";<br>&nbsp; &nbsp; }<br>}</tt></p></div> </blockquote><p>If you are going to create an object for something, you HAVE to be sure that the objects are trustworthy.</p><p>And so you should never allow objects to exist that are invalid. EVERY object should be a valid object.</p><p>At the absolute minimum objects should be able to default every attribute to something reasonable and unlikely to cause problems.</p><p>But this still results in excess and wasteful work, because the object has to transition through two or more states.</p><p>You start with an object with parameters and defaults, and you validate them. And then you change on of the attributes immediately, validating it AGAIN. In the mean time, your object exists in a state that it will never actually be used in.</p><p>And so everywhere you possibly can, you should be setting attributes in the constructor rather than afterwards.</p><blockquote><div><p> <tt>my $object = Class-&gt;new(<br>&nbsp; &nbsp; foo =&gt; 1,<br>&nbsp; &nbsp; bar =&gt; 2,<br>);<br>$object-&gt;do_something;</tt></p></div> </blockquote><p>Less state, less complexity, less CPU, and less bugs.</p><p>If we accept this model of pushing all the configuration into the object up front to reduce state, then why change the object arbitrarily?</p><p>In fact, anything that you ARE going to change should be done under very controlled conditions.</p><p>It should require a dedicated method to apply the change, it should require validation, and work. It shouldn't be trivial, and it shouldn't be automatic.</p><p>If I had my way, Moose would set is =&gt; 'ro' by default, to make people think before they go about simply allowing stuff to change.</p><p>It also happens to let you shrink down the API markedly.</p><p>There are three potential use cases available when implementing accessors. Everything readonly, everything readwrite, or mixed.</p><p>With Object::Tiny, I was aiming for the smallest possible code.</p><p>Implementing either all-readonly or all-readwrite can be done with the following.</p><blockquote><div><p> <tt>use Class qw{<br>&nbsp; &nbsp; foo<br>&nbsp; &nbsp; bar<br>};</tt></p></div> </blockquote><p>By contrast, if we want to allow mixed readonly and readwrite, we would need some way of distinguishing. Something like the following.</p><blockquote><div><p> <tt>use Class {<br>&nbsp; &nbsp; readonly =&gt; [ 'foo' ],<br>&nbsp; &nbsp; readwrite =&gt; [ 'bar' ],<br>};<br> &nbsp; <br>use Class [ qw{<br>&nbsp; &nbsp; foo<br>} ], [ {<br>&nbsp; &nbsp; bar<br>} ];<br> &nbsp; <br>use Class {<br>&nbsp; &nbsp; foo =&gt; 'ro',<br>&nbsp; &nbsp; bar =&gt; 'rw',<br>};</tt></p></div> </blockquote><p>No matter how you try, there's always an inherent additional element of complexity that results from the split between them.</p><p>And so the decision to go with all-readonly in Object::Tiny is a combination of these two issues.</p><p>If went with all-readwrite, I'm practically encouraging bad behaviour and more bugs. If I went with mixed accessors, the API would remain relative complex.</p><p>In the end, the best way to achieve both API simplicity and code safety is to only provide read-only accessors, and anything more complex should require both though and effort.</p> Alias 2010-08-15T01:39:50+00:00 journal Trailer Theory - Reinvented for Ignite Sydney as Economics http://use.perl.org/~Alias/journal/40480?from=rss <p>Back in 2005 in <a href="http://use.perl.org/~Alias/journal/23820">only my fifth use.perl post ever</a>, I outlined an idea I had been developing for a couple of years that I called "Trailer Theory".</p><p>A few years ago on my Portable Perl world hack'a'tour, I took with me a lightning talk version of the concept. It was a pretty crude talk but was received, it seemed, fairly well by the development community.</p><p>Since that trip, and inspired by the unexpected conversion of my "Perl is unparsable" claims in the PPI docs into a formal mathematical proof (complete with "Kennedy's Lemma") I've been wondering if this "Trailer Theory" idea could really be developed as a proper scientific proof, and if so what would that look like.</p><p>A couple of months ago I presented a new version of the talk at Ignite Sydney, speaking to an mixed audience of Twitterati, social media, advertising and journalist types.</p><p>I've rebuilt the talk from scratch and tried to outline the same idea, but in the form of a kind of layman's Economics Proof.</p><p>I hope you enjoy the result.</p><p><a href="http://igniteshow.com/videos/using-economics-make-movies-suck-less">Adam Kennedy - Using Economics to make movies suck less</a></p><p><i><br>Notes for other speakers:</i></p><p><i>1. Ignite advances slides every 15 seconds, no clickers allowed. This turns out to take a shitload of practice to get right.</i></p><p><i>2. When someone says to you "Here's your mark, you need to stay on this line to be in the fixed spot" it helps to pay attention. FAIL<nobr> <wbr></nobr>:)<br></i></p> Alias 2010-08-04T05:40:53+00:00 journal Protesting the Moose with sugary alternatives http://use.perl.org/~Alias/journal/40477?from=rss <p>At work, we've been experimenting with Moose because in our enormous and complex codebase we think we can probably benefit a lot from the extra rigour that it brings.</p><p>Before I continue, let me note that ours is a typical mod_perl enterprise setup with 6gig of memory per machine, so any memory consumed before the Apache fork is essentially free.</p><p>So none of the issues people (including me) have with startup code and memory consumption apply in this case, and I won't be addressing performance issues in this post.</p><p>The consensus of the half-dozen people at work is how Moose tries to look like a declarative extension, but doesn't actually act like it.</p><p>The following is what Moose seems to have been aiming for.</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use Moose;<br> &nbsp; <br>extends 'Bar';<br>with&nbsp; &nbsp; 'Role1';<br>with&nbsp; &nbsp; 'Role2';<br> &nbsp; <br>has this =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>has that =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>1;</tt></p></div> </blockquote><p>Unfortunately, this is what we've had to do instead.</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use Moose;<br> &nbsp; <br>BEGIN { # When we use Catalyst<br>&nbsp; &nbsp; extends 'Bar';<br>}<br> &nbsp; <br>has this =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>has that =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>with&nbsp; &nbsp; 'Role1';<br>with&nbsp; &nbsp; 'Role2';<br>no Moose;<br>__PACKAGE-&gt;meta-&gt;make_immutable;</tt></p></div> </blockquote><p>This "real Moose" code totally spoils the dream of what we felt like we were going to get when we started to play with it.</p><p>Most of our current options for fixing this amount to either.</p><p>a) Add this extra dependency that will unscrew one of the other of the problems (namespace::autoclean)</p><p>b) Use this SECOND heavy sugar layer on top of the FIRST sugar layer, on top of Class::MOP.</p><p>Is fixing the syntax or writing light weight sugar really so hard?</p><p>As a kind of protest, I tried it for myself and managed to create <a href="http://search.cpan.org/perldoc?MooseX::Atom">MooseX::Atom</a>.</p><p>This still has some flaws, but the current equivalent of the above would just be this.</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use MooseX::Atom [<br>&nbsp; &nbsp; extends =&gt; 'Bar',<br>&nbsp; &nbsp; with&nbsp; &nbsp; =&gt; 'Role1',<br>&nbsp; &nbsp; with&nbsp; &nbsp; =&gt; 'Role2',<br>&nbsp; &nbsp; has&nbsp; &nbsp; &nbsp;=&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this =&gt; (<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isa =&gt; 'Str',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;),<br>&nbsp; &nbsp; ],<br>&nbsp; &nbsp; has&nbsp; &nbsp; &nbsp;=&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;that =&gt; (<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isa =&gt; 'Str',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;),<br>&nbsp; &nbsp; ]<br>];<br> &nbsp; <br>1;</tt></p></div> </blockquote><p>You can do the same thing for roles with <a href="http://search.cpan.org/perldoc?MooseX::Role::Atom">MooseX::Role::Atom</a>.</p><p>Now clearly, this might have some issues. It's the work of an hour and not a whole lot of thought.</p><p>But it's still light and clean, with all the class spec in one place up the top where people are used to seeing the declarative stuff in Perl modules.</p><p>Perhaps something like this might be a little better...</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use MooseX::Hash {<br>&nbsp; &nbsp; extends =&gt; 'Bar',<br>&nbsp; &nbsp; with&nbsp; &nbsp; =&gt; [ 'Role1', 'Role2' ],<br>&nbsp; &nbsp; default =&gt; { is =&gt; 'ro' },<br>&nbsp; &nbsp; has&nbsp; &nbsp; &nbsp;=&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; this =&gt; { isa =&gt; 'Str' },<br>&nbsp; &nbsp; &nbsp; &nbsp; that =&gt; { isa =&gt; 'Str' },<br>&nbsp; &nbsp; },<br>);<br> &nbsp; <br>1;</tt></p></div> </blockquote> Alias 2010-08-03T05:09:02+00:00 journal Help? http://use.perl.org/~Alias/journal/40470?from=rss <p>(Before I begin, I should clarify I did not write this code, I'm just trying to maintain it)</p><p>The following error is the first thing spat out by make test for the Padre sync server, located at <a href="http://svn.perlide.org/padre/trunk/Madre-Sync">http://svn.perlide.org/padre/trunk/Madre-Sync</a>.</p><p>Wasn't the move of Catalyst to Moose going to make things easier?</p><p>Can someone explain how you debug this?</p><p>I get the basics, I can see the "Can't locate Madre/Sync/Schema.pm". But that file should be, I think, automatically generated. And I don't really get how to dig down the 75 caller levels from the start to the end to work out where the actual functionality is failing...</p><blockquote><div><p> <tt>not ok 1 - use Catalyst::Test;<br> &nbsp; <br>#&nbsp; &nbsp;Failed test 'use Catalyst::Test;'<br>#&nbsp; &nbsp;at t\01app.t line 7.<br>#&nbsp; &nbsp; &nbsp;Tried to use 'Catalyst::Test'.<br>#&nbsp; &nbsp; &nbsp;Error:&nbsp; Couldn't load class (Madre::Sync) because: Couldn't instantiate component "Madre::Sync::Model::padreDB", "Can't locate Madre/Sync/Schema.pm i<br>n @INC (@INC contains: blib\lib blib\arch C:/strawberry/perl/lib C:/strawberry/perl/site/lib C:\strawberry\perl\vendor\lib<nobr> <wbr></nobr>.). at C:\strawberry\perl\vendor<br>\lib/Class/MOP.pm line 132<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Catalyst/Model/DBIC/Schema/Types.pm line 21<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::Types::__ANON__[C:\strawberry\perl\vendor\lib/C<nobr>a<wbr></nobr> talyst/Model/DBIC/Schema/Types.pm:21]('Madre::Sync::Schema') called<br>at C:\strawberry\perl\vendor\lib/Moose/Meta/TypeCoercion.pm line 63<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::TypeCoercion::__ANON__[C:\strawberry\perl\vendor\lib/Moose/Meta/T<nobr>y<wbr></nobr> peCoercion.pm:67]('Madre::Sync::Schema') called at C:\strawberry\per<br>l\vendor\lib/Moose/Meta/TypeCoercion.pm line 97<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::TypeCoercion::coerce('Moose::Meta::TypeCoercion=HASH(0x4a2b444)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Moose<br>/Meta/TypeConstraint.pm line 90<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::TypeConstraint::coerce('Moose::Meta::TypeConstraint=HASH(0x4a2985<nobr>4<wbr></nobr> )', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/M<br>ooseX/Types/TypeDecorator.pm line 206<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/MooseX/Types/TypeDecorator.pm line 205<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Types::TypeDecorator::AUTOLOAD('MooseX::Types::TypeDecorator=HASH(0x4a<nobr>3<wbr></nobr> 1424)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\l<br>ib/Moose/Meta/Attribute.pm line 743<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::_coerce_and_verify('Moose::Meta::Attribute=HASH(0x4b46<nobr>7<wbr></nobr> fc)', 'Madre::Sync::Schema', 'Madre::Sync::Model::padreDB=HASH(0x4db<br>7c64)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Attribute.pm line 398<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::initialize_instance_slot('Moose::Meta::Attribute=HASH(<nobr>0<wbr></nobr> x4b467fc)', 'Moose::Meta::Instance=HASH(0x4db7ed4)', 'Madre::Sync::M<br>odel::padreDB=HASH(0x4db7c64)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Class.pm line 567<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::_construct_instance('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/C<br>lass.pm line 540<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Class.pm<br>line 256<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Object.pm lin<br>e 25<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Object::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at generated method (unknown origin) line 4<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at C:\strawberry\perl\vendor\lib/MooseX/<br>Traits/Pluggable.pm line 131<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Traits::Pluggable::new_with_traits('Madre::Sync::Model::padreDB', 'Madre::Sync') called at C:\strawberry\perl\vendor\lib/CatalystX/Componen<br>t/Traits.pm line 146<br>#&nbsp; &nbsp; &nbsp; &nbsp;CatalystX::Component::Traits::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Cl<br>ass/MOP/Method/Wrapped.pm line 48<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:49]('Madre::Sync::Model::padreDB', 'Madre::Sync', '<br>HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/C<br>atalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_component('Madre::Sync', 'Madre::Sync::Model::padreDB') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2416<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 54<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:64]('Madre::Sync') called at C:\strawberry\perl\ven<br>dor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Madre::Sync::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 1142<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup('Madre::Sync') called at blib\lib/Madre/Sync.pm line 62<br>#&nbsp; &nbsp; &nbsp; &nbsp;require Madre/Sync.pm called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 114<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:118]() called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 74<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 67<br>#&nbsp; &nbsp; &nbsp; &nbsp;Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('C<nobr>a<wbr></nobr> talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a<br>t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call<br>ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S<br>ub/Exporter.pm line 742<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Ca<nobr>t<wbr></nobr> alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per<br>l\vendor\lib/Catalyst/Test.pm line 112<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;main::BEGIN() called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval 'package main;<br># use Catalyst::Test @{$args[0]};<br># 1;<br>#<br>#<nobr> <wbr></nobr>;' called at C:/strawberry/perl/lib/Test/More.pm line 858<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p<br>m line 833<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7<br>#&nbsp; at C:\strawberry\perl\vendor\lib/MooseX/Types/TypeDecorator.pm line 208<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Types::TypeDecorator::AUTOLOAD('MooseX::Types::TypeDecorator=HASH(0x4a<nobr>3<wbr></nobr> 1424)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\l<br>ib/Moose/Meta/Attribute.pm line 743<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::_coerce_and_verify('Moose::Meta::Attribute=HASH(0x4b46<nobr>7<wbr></nobr> fc)', 'Madre::Sync::Schema', 'Madre::Sync::Model::padreDB=HASH(0x4db<br>7c64)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Attribute.pm line 398<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::initialize_instance_slot('Moose::Meta::Attribute=HASH(<nobr>0<wbr></nobr> x4b467fc)', 'Moose::Meta::Instance=HASH(0x4db7ed4)', 'Madre::Sync::M<br>odel::padreDB=HASH(0x4db7c64)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Class.pm line 567<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::_construct_instance('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/C<br>lass.pm line 540<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Class.pm<br>line 256<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Object.pm lin<br>e 25<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Object::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at generated method (unknown origin) line 4<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at C:\strawberry\perl\vendor\lib/MooseX/<br>Traits/Pluggable.pm line 131<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Traits::Pluggable::new_with_traits('Madre::Sync::Model::padreDB', 'Madre::Sync') called at C:\strawberry\perl\vendor\lib/CatalystX/Componen<br>t/Traits.pm line 146<br>#&nbsp; &nbsp; &nbsp; &nbsp;CatalystX::Component::Traits::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Cl<br>ass/MOP/Method/Wrapped.pm line 48<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:49]('Madre::Sync::Model::padreDB', 'Madre::Sync', '<br>HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/C<br>atalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_component('Madre::Sync', 'Madre::Sync::Model::padreDB') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2416<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 54<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:64]('Madre::Sync') called at C:\strawberry\perl\ven<br>dor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Madre::Sync::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 1142<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup('Madre::Sync') called at blib\lib/Madre/Sync.pm line 62<br>#&nbsp; &nbsp; &nbsp; &nbsp;require Madre/Sync.pm called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 114<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:118]() called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 74<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 67<br>#&nbsp; &nbsp; &nbsp; &nbsp;Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('C<nobr>a<wbr></nobr> talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a<br>t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call<br>ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S<br>ub/Exporter.pm line 742<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Ca<nobr>t<wbr></nobr> alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per<br>l\vendor\lib/Catalyst/Test.pm line 112<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;main::BEGIN() called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval 'package main;<br># use Catalyst::Test @{$args[0]};<br># 1;<br>#<br>#<nobr> <wbr></nobr>;' called at C:/strawberry/perl/lib/Test/More.pm line 858<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p<br>m line 833<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7"Compilation failed in require at C:\strawberry\perl\vendor\lib/Class<br>/MOP.pm line 114.<br>#&nbsp; at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 121<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:125]('Couldn\'<nobr>t<wbr></nobr> instantiate component "Madre::Sync::Model::padreDB"...') called at<br>C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 98<br>#&nbsp; &nbsp; &nbsp; &nbsp;Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('C<nobr>a<wbr></nobr> talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a<br>t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call<br>ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S<br>ub/Exporter.pm line 742<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Ca<nobr>t<wbr></nobr> alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per<br>l\vendor\lib/Catalyst/Test.pm line 112<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;main::BEGIN() called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval 'package main;<br># use Catalyst::Test @{$args[0]};<br># 1;<br>#<br>#<nobr> <wbr></nobr>;' called at C:/strawberry/perl/lib/Test/More.pm line 858<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p<br>m line 833<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7<br># BEGIN failed--compilation aborted at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2.</tt></p></div> </blockquote> Alias 2010-07-29T13:23:44+00:00 journal For people running Perl conferences http://use.perl.org/~Alias/journal/40461?from=rss <p>Leo Lapworth comments in <a href="http://blogs.perl.org/users/leo_lapworth/2010/07/for-speakers-at-perl-conferences.html">"For speakers at Perl conferences"</a> that you should record your own talks at conferences, because organisers cannot be trusted to release the videos they take of you.</p><p>I wholeheartedly agree. I've spoken at numerous conferences, including several large ones, and only in about 10-20% of cases have the videos of me EVER appeared.</p><p>I'm amazed that conference organisers can put in so much effort into recording (dozens of tapes, multiple cameras, multiple operators) and then never produce anything as a result.</p><p>The only time I'm aware of that a full talk of mine has appeared online was at a Linux.conf.au, who had a dedicated video team of eight people.</p><p>Where is all this footage, and why does it never get processed? Why even bother recording it? If you don't have time, send me the raw tape of my own talk and I will do it myself if needed.</p><p>YAPC::NA? You listening?</p> Alias 2010-07-25T12:55:04+00:00 journal A reminder - Padre Second Birthday Hackathon this weekend http://use.perl.org/~Alias/journal/40460?from=rss <p>This is just a quick reminder that this weekend is the Padre's second birthday party and hackathon.</p><p>If you are a Padre user, please drop in and say hello to the team. We'd love to hear how you are using Padre and where your main needs are for the next year.</p><p>If you are interested in trying out Padre for the first time, or trying your hand at improving it for the first time, it's a great time to get started because we'll have plenty of people around to provide guidance and advice.</p><p>Some of the plans for this weekend are to bring all the plugins up to date with the latest versions of the plugin API, to start the merge of the ConfigSync branch, and if we can, to start on the Madre server that will serve as the ConfigSync and Telemetry server for Padre.</p><p>I look forward to seeing you there!</p> Alias 2010-07-23T03:53:28+00:00 journal Profiling your website while live on a production cluster http://use.perl.org/~Alias/journal/40457?from=rss <p>As I mentioned in my last post, by day I wrangle a large web application that occasionally verges on being too complex to for mere humans to understand.</p><p>Curiously, because it is private and the income rate is high (we probably average something like $5 in gross turnover per page view) we don't have to deal with a lot of servers to deliver it, by internet standards anyway.</p><p>But the application is still way too big to profile easily by normal methods, and certainly on production it's way too heavy, even if we applied targeted profiling using something like <a href="http://search.cpan.org/perldoc?Aspect::Library::NYTProf">Aspect::Library::NYTProf</a>.</p><p>Between the web servers, transaction server, database, search engine and cache server, we are probably only dealing with 12 servers and 30 CPUs. Of course, these servers are all horribly expensive, because they are all server-virtualised, network-virtualised, doubly redundant (high-availability + disaster-recovery) and heavily monitored with high end support contracts.</p><p>One of our most sensitive issues is database load.</p><p>We have a ton of database tables (about 200) and lots of medium sized queries running across them. One of our main failure modes is that some deep change to code boosts the quantity of some significant query, which stresses the database enough to cause contention and lock-storms, leading to site failure.</p><p>Complicating things, big parts of some pages are embedded in other pages. So attributing load and lag to one part of the website, or to Oracle, is tricky and hard to benchmark in advance (although we do load test the main load paths to catch the worst cases).</p><p>For a long time, we've had a mechanism for zoned profiling the production site, so we can allocate wallclock costs to different general areas of the site.</p><p>But it is fragile and unreliable, requiring perfect maintenance and every developer to remember to write this kind of thing everywhere.</p><blockquote><div><p> <tt># Embed a foo widget in the current page<br>$perf-&gt;push_timing('foo');<br>foo($bar);<br>$perf-&gt;pop_timing;</tt></p></div> </blockquote><p>Since you don't know this profiling system exists unless you've seen it somewhere else in the code before, and it's hard to care about something that is orthogonal to the problem you are actuall solving, this mechanism has degraded over time. While we still get some pretty cacti graphs showing load breakdown, they are highly unreliable and you can never be entirely sure if the load attribution is correct.</p><p>This kind of performance monitoring as a "cross-cutting concern" is a textbook use case for Aspect-Oriented Programming, and so in our Christmas 2009 code freeze window I set about trying to rewrite the push/pop_timing profiler using <a href="http://search.cpan.org/perldoc?Aspect">Aspect.pm</a>.</p><p>Unfortunately, Aspect.pm turned out to be a bit too slow and naive for my needs. But after a 6 month delay to do a 90% rewrite of Aspect.pm, I now finally have something sophisticated enough (and fast enough) to meet my needs.</p><p>So today I'm releasing the shiny new <a href="http://search.cpan.org/perldoc?Aspect::Library::ZoneTimer">Aspect::Library::ZoneTimer</a>, which will serve as the main plank of our new production profiling system.</p><p>The idea behind ZoneTimer is to define each performance zone as a pointcut. The aspect will track the movement of your code across each zone boundaries and build a running total of the exclusive time spent in each performance zone.</p><p>When your program exits the top-most performance zone, the totals will be sent to a handler function.</p><p>A typical use of the ZoneTimer aspect looks something like this</p><blockquote><div><p> <tt>use Aspect;<br> &nbsp; <br>aspect ZoneTimer =&gt; (<br>&nbsp; &nbsp; zones =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; main&nbsp; &nbsp; &nbsp; =&gt; call 'MyProgram::main' &amp; highest,<br>&nbsp; &nbsp; &nbsp; &nbsp; search&nbsp; &nbsp; =&gt; call 'MyProgram::search',<br>&nbsp; &nbsp; &nbsp; &nbsp; widgets&nbsp; &nbsp;=&gt; call qr/^MyProgram::widget_.*/,<br>&nbsp; &nbsp; &nbsp; &nbsp; templates =&gt; call 'MyProgram::render',<br>&nbsp; &nbsp; &nbsp; &nbsp; dbi&nbsp; &nbsp; &nbsp; &nbsp;=&gt; call qr/^DB[DI]::.*?\b(?:prepare|execute|fetch.*)$/,<br>&nbsp; &nbsp; &nbsp; &nbsp; system&nbsp; &nbsp; =&gt; (<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call qr/^IPC::System::Simple::(?:run|runx|capture)/<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call 'IPC::Run3::run3'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call qr/^Capture::Tiny::(?:capture|tee).*/<br>&nbsp; &nbsp; &nbsp; &nbsp; )<br>&nbsp; &nbsp; },<br>&nbsp; &nbsp; handler =&gt; sub {<br>&nbsp; &nbsp; &nbsp; &nbsp; my $top&nbsp; &nbsp; &nbsp; &nbsp;= shift; # "main"<br>&nbsp; &nbsp; &nbsp; &nbsp; my $start&nbsp; &nbsp; &nbsp;= shift; # [ 1279763446, 796875 ]<br>&nbsp; &nbsp; &nbsp; &nbsp; my $stop&nbsp; &nbsp; &nbsp; = shift; # [ 1279763473, 163153 ]<br>&nbsp; &nbsp; &nbsp; &nbsp; my $exclusive = shift; # { main =&gt; 23123412, dbi =&gt; 3231231 }<br> &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; print "Profiling from zone $top\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; print "Started recording at " . scalar(localtime $start) . "\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; print "Stopped recording at " . scalar(localtime $stop)&nbsp; . "\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; foreach my $zone ( sort keys %$exclusive ) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print "Spent $exclusive-&gt;{$zone} microseconds in zone $zone\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; },<br>);</tt></p></div> </blockquote><p>This example breaks out the cost of a typical small web application into a general zone, a special zone for the search page, and then splits the costs of generating widgets, rendering the HTML template, waiting for the database, and making calls to the underlying system.</p><p>Start and stop times are returned as a two element array exactly as returned by C, and the exclusive zone totals are returned as integer microseconds (all math is done in these integer microseconds to prevent floating point corruption).</p><p>The use of Aspect allows us to easily mix special cases via the pointcuts, such as the use of "highest" which makes sure that "main" only matches the first time it is seen, and any widget which that does a re-entry into main still has that cost attributed to the widget. We've also hooked into multiple system call modules to measure system call cost, because we know different modules our program consumes will use different methods for interacting with the system.</p><p>While the handler I've shown here will just print out a summary of the call, in our environment at work the profile report handler will format the exclusive times into a special log message and then send it via the super-quick and non-blocking <a href="http://search.cpan.org/perldoc?Log::Syslog::Fast">Log::Syslog::Fast</a> module to the UDP localhost syslog service, where it is mirrored to disk for debugging use, and then forwarded on to our main company-wide syslog server.</p><p>On our setup, we can then use an excellent commercial log analysis product called <a href="http://www.splunk.com/">Splunk</a> (limited free version also available if you want to try it out) to do our tracking and trending of the performance for the entire application across the entire cluster.</p><p>The nicest thing about the Aspect system is that it scales the performance cost and complexity risk directly to the complexity of the use case you are using it for.</p><p>If it turns out that the Aspect hooks are too intrusive and causing a performance drain, or accidentally causing some weird edge case behaviour, you can simply turn off that the Aspect and restart the servers and the performance penalty just vanishes.</p><p>Maintenance of the profiler zones is really easy, because they are all listed clearly in one place.</p><p>Depending on your use case, you could even define the performance zones in your website configuration, and then adjust the profiler zone boundaries directly on production (although I'm not sure I'd want to do that in our specific case, since we're fairly paranoid about untested code going into production).</p><p>This ZoneTimer is just the first of several Aspect-based tools I plan to release over the next few months. If you get a chance to try out any of these new toys, I'd love to hear feedback on how well they work for you.</p><p>In addition to the value of the ZoneTimer aspect itself, one other thing that some people might find of interest is just how little code it took to get this all working.</p><p>The entire Aspect::Library::ZoneTimer was implemented in about 80 lines of code, which you can see at <a href="http://cpansearch.perl.org/src/ADAMK/Aspect-Library-Timer-0.04/lib/Aspect/Library/ZoneTimer.pm">http://cpansearch.perl.org/src/ADAMK/Aspect-Library-Timer-0.04/lib/Aspect/Libra<nobr>r<wbr></nobr> y/ZoneTimer.pm</a></p><p>This is small enough that you could just clone the module and tweak it for your own use case, if you wanted to creat a new and tricky customised profiler.</p> Alias 2010-07-22T02:27:33+00:00 journal How we deploy massive Perl applications at work http://use.perl.org/~Alias/journal/40453?from=rss <p>Every now and then, we hear people talking about mechanisms for doing Perl in a commercial environment and how they deal with packaging and dependencies.</p><p>This is mine.</p><p>At Corporate Express, our main Perl application is a 250,000 line non-public monster of a website that has over 100,000 physical users and turns over about a billion dollars. It implements huge amounts of complex business functionality, and has layer upon layer of security and reliability functions in it because we supply to multinationals, governments and the military (only the stuff that doesn't blow up of course). Our<nobr> <wbr></nobr>.pm file count is around 750, and our test suite runs for about 4 hours (and is only around one third complete).</p><p>Lest you suspect that 200,000 lines is wasted in re-implementing stuff, the main Build.PL script has around 110 DIRECT dependencies, and somewhere in the 300-500 range of recursive dependencies. Loading the main codebase into memory takes around 150-200meg of RAM.</p><p>When I joined the team, the build system was horribly out of date. The application was stuck on an old version of RedHat due to go out of support, and as a Tier 1 application we are absolutely forbidden from using unsupported platform.</p><p>So I took on the task of upgrading both the operating system and the build system for the project. And it's a build system with a history.</p><p>Once upon a time, long ago, the project went through a period where the development team was exceptionally strong and high skilled. And so of course, they created a roll-your-own build system called "VBuild".</p><p>They built their own Perl, and along with it they also built their own Apache, mod_perl, and half a dozen other things needed by the project. This is similar to many suggestions I hear from high-skilled people today, that at a certain point it's better just to build your own Perl. VBuild this created in the pre-commercial Linux era, so it's not an entirely unreasonable decision for that time period.</p><p>Unfortunately, a few years later the quality of the team dropped off and VBuild turned into a maintenance nightmare because it required a high-skill person to maintain it.</p><p>At the time, the Tier 1 "Must be supported" policy was coming into effect, and after the problems with custom-compiling they decided to go with the completely opposite approach of using only vendor provided packages, in a system called "UnVBuild".</p><p>Since their platform of choice was RedHat, this had become troublesome even before I arrived. Worse, in the change from RHEL 4 to RHEL 5, some of the vendor packages for things like XSLT support were dropped entirely leaving us in a bind.</p><p>My first instinct was to return to the build everything approach, but the stories (and commit commentary) from that time period reinforced the idea that complete custom build was a bad idea. Office supplies is hardly a sexy industry, and the ability to entice good developers into it is a quite legitimate risk.</p><p>So in the end, I went with an approach we ended up nicknaming "HalfBuild". The concept behind it is "Vendor where possible, build where needed".</p><p>We use a fairly reasonable chunk of vendor packages under this model. Perl itself, the Oracle client, XML::LibXML and a variety of other things where our version needs are modest and RHEL5 contains it. We also use a ton of C libraries from RHEL5 that are consumed by the CPAN modules, like all the image libraries needed by Imager, some PDF and Postscript libraries, and so on.</p><p>One RPM "platform-deps" meta-package defines the full list of these system dependencies, and that RPM is maintained exclusively by server operations so that we as developers are cryptographically unable to add major non-Perl dependencies without consulting them first.</p><p>On top of this is one enormous "platform-cpan" RPM package built by the dev team that contains every single CPAN dependency needed by all of our Perl projects.</p><p>This package lives in its own home at<nobr> <wbr></nobr>/opt/cpan and is built using a process rather similar to the core parts of Strawberry Perl. With PREFIX pointing into<nobr> <wbr></nobr>/opt/cpan, we first build a hand-crafted list of distribution tarballs to upgrade RHEL5 to a modern install of CPAN.pm (without overwriting any normal system files).</p><p>We then boot up the CPAN client from<nobr> <wbr></nobr>/opt/cpan, and tell it to install all the rest of the dependencies from a private internal CPAN mirror which is rsynced by hand specifically for each new CPAN build. This ensures that the build process is deterministic, and that we can fix bugs in the build process if we need to without being forced to upgrade the modules themselves).</p><p>The CPAN client grinds away installing for an hour, and then we're left with our "CPAN Layer", which we can include in our application with some simple changes to @INC at the beginning of our bootstrapping module.</p><p>The<nobr> <wbr></nobr>/opt/cpan directory for our project currently weighs in at about 110meg and contains 2,335<nobr> <wbr></nobr>.pm files.</p><p>Updating<nobr> <wbr></nobr>/opt/cpan is still something of an exercise even under this model because of potential upgrade problems (Moose forbidding +attributes in roles hit us on our most recent upgrade) but the whole process is fully automated from end to end, and can be maintained by a medium-skill Perl hacker, rather than needing an uberhacker.</p><p>Over the last 2 years, we've upgraded it around once every 6 months and usually because we needed to add five or ten more dependencies. We tend to add these new dependencies as early as we can, when work that needs them is confirmed but unscheduled.</p><p>We also resort to the occasional hand-copied or inlined pure-Perl<nobr> <wbr></nobr>.pm file in emergencies, but this is temporary and we only do so about once a year when caught unprepared (most recently Text::Unidecode for some "emergency ascii'fication" of data where Unicode had accidentally slipped in).</p><p>While not ideal, we've been quite happy with the<nobr> <wbr></nobr>/opt/cpan approach so far.</p><p>It means we only have to maintain 5 RPM packages rather than 500, and updating it takes one or two man-days per 6 months, if there aren't any API changes in the upgrade.</p><p>And most importantly it provides us with much better bus sensitivity, which is hugely important in applications with working lives measured in decades.</p> Alias 2010-07-20T02:25:21+00:00 journal Padre Second Birthday Party 24th-25th of July http://use.perl.org/~Alias/journal/40441?from=rss <p>2 years ago this month, Gabor did the first Padre release.</p><p>The last 12 months has seen Padre mature from a high-end text editor to a low-end refactoring IDE. We've stolen a number of features from Ultraedit, Komodo and EPIC, and we've invented new features all of our own, making Padre a very fluid and natural place to write Perl in.</p><p>We've added support for Perl 6, Template Toolkit, remote file support, more languages, syntax checking, an interactive debugger, a regex editor, and our first half a dozen refactoring tools.</p><p>We've also greatly solidified the code. Window integration is now totally solid, we've added a resource locking API, a new filesystem API, a new search API, a new display API, rewritten the threading and background Task subsystem, heavily overhauled the Plugin Manager API and GUI, and added Advanced Preferences and the ability for advanced users to selective disable various Padre bloat/features.</p><p>The last couple of months have also seen great improvements in Padre's hackability as well. The new Task 2.0 API lets people write background logic and consume multiple cores of CPU without having to know how threading works, and the new wxFormBuilder plugin lets you build GUI code without having to know Wx (one of the biggest barriers to contributing to Padre).</p><p>On the weekend of the 24th-25th of July we would like to invite all Padre developers, users, friends and well-wishers to join us for Padre's Second Birthday Party and Hackathon in the Padre IRC channel at <a href="irc:ircperlorgpadre">irc://irc.perl.org/#padre</a> or via the <a href="http://widget.mibbit.com/?server=irc.perl.org&amp;channel=%23padre">Mibbit Web Client</a>.</p><p>If you've always been curious about, or interested in hacking on, Padre we'll have a number of developers in channel to help you out.</p><p>Personally, I plan to debut the first public release of Padre::Plugin::FormBuilder, and to start ripping out all Padre's older fixed-size dialogs and replacing them with new shiny model-generated sizer-based dialogs that will work much better across all three operating systems.</p><p>If you'd like to help out in this effort, I'll be in channel most of the day on both days (Sydney timezone).</p><p>I look forward to seeing you all there.</p> Alias 2010-07-10T16:50:21+00:00 journal Yahoo provides (awesome) alternative Geocoder to Google's http://use.perl.org/~Alias/journal/40436?from=rss <p>As far as I'm concerned, there are three critical things you need in a Geocoder service.</p><p>1. Global Coverage</p><p>Because when it doesn't have global coverage, it's basically means "America-only" and thus pointless for most of the world.</p><p>2. Multiple Matching</p><p>For ordinary humans, there's massive power in being able to just search for "1 Oxford Street" without listing any more details. From there, if it is a country-specific application you just change it to "1 Oxford Street, Australia" behind the scenes.</p><p>That results in a list of possible locations.</p><p>You show the results for the first result, and then a list of "Did you mean:" links for the other results. This lets the application do what people mean most of the time, while making it trivial to recover if it isn't accurate enough.</p><p>You can see the effect I'm talking about by running the example query here...</p><p><a href="http://geo2gov.com.au/">http://geo2gov.com.au/</a></p><p>3. No usage limitations</p><p>Google Maps Geocoder can only be used with Google Maps. Fail.</p><p>I'm willing to accept a volume limitation like "You have to pay after the first 50,000 requests" but I can't accept a usage limitation.</p><p>I'm happy to report that Yahoo's new PlaceFinder service is the first free Geocoder that meets all these primary criteria.</p><p>It's global in scope, lets you control the list of results with paging, and doesn't limit the usage to any particular domain.</p><p>Now all we need is an Geo::Coder plugin for it.</p><p>Please write one for me Lazyweb<nobr> <wbr></nobr>:)</p> Alias 2010-07-06T04:10:06+00:00 journal The next challenge for Perl on Windows (et al) http://use.perl.org/~Alias/journal/40424?from=rss <p>Even at this early stage, before any actual installers have appeared, things are looking pretty good for Strawberry Professional Alpha 2.</p><p>Padre is starting to firm up as a usable editor, Frozen Bubble works quite well and is completely playable, and I think my wxFormBuilder work is coming along nicely (which bodes well for quickly and easily creating GUI apps in some Alpha 3...)</p><p>My biggest remaining concern at the moment though, is also one of the smallest and seemingly trivial issues.</p><p>Although we can much more easily build and install large, rich and good looking desktop applications there is still no way to launch these applications without resorting to the command line.</p><p>Any iconography that are filled into the start menu in Strawberry Professional will do so because Curtis has put them there himself.</p><p>A Perl installation, via the %Config information, lets an installer know where to put libraries, binaries, documentation etc. Shared files in the File::ShareDir model are really just a hack, putting them in an agreed location within lib.</p><p>File::HomeDir isn't any use to us either for this. It is designed to let programs deal with user-owned data at run-time, NOT with system integration at install time.</p><p>Without the ability to install programs in a way that desktop users can easily launch, our little nascent desktop revolution will never really be able to get up to speed.</p><p>Having a post-install step where you need to launch a Windows command line, and then run "padre --desktop" just to install a desktop icon is simply not good enough.</p><p>Likewise, having to run Frozen Bubble from the command line is silly as well.</p><p>So consider this a challenge to anyone out there that likes tackling tricky puzzles, to try and build a File::Launcher (or whatever you want to call it) that can locate install paths, and be integrated into module installers, so we can make proper use of the Start Menu, Desktop, Quick Launcher, and all the equivalent features on all three major desktop platforms (Windows, Mac, and FreeDesktop.org).</p><p>If you build it, Padre will use it.</p> Alias 2010-07-01T03:32:16+00:00 journal I hereby report the success of my 2005 Perl Foundation Grant http://use.perl.org/~Alias/journal/40398?from=rss <p>In late 2005 I was awarded a grant from the Perl Foundation for "Extending PPI Towards a Refactoring Perl Editor". You can see the original grant here.</p><p><a href="http://www.perlfoundation.org/adam_kennedy_extending_ppi_towards_a_refactoring_perl_editor">http://www.perlfoundation.org/adam_kennedy_extending_ppi_towards_a_refactoring_<nobr>p<wbr></nobr> erl_editor</a></p><p>My idea at the time was to take the recently completed <a href="http://search.cpan.org/perldoc?PPI">PPI</a> parser, fill in a variety of different supporting features, build some modules to improve platform integration, and then build a refactoring editor that used PPI and that would fire the imagination of what was possible in Perl.</p><p>A year and a half later in early 2007, I was forced to report the failure of the grant.</p><p><a href="http://www.perlfoundation.org/march_25_2007_adam_kennedy_s_refactoring_editor_grant">http://www.perlfoundation.org/march_25_2007_adam_kennedy_s_refactoring_editor_g<nobr>r<wbr></nobr> ant</a></p><p>Not having anything like the time or experience to build an editor from scratch, I had intended to build a thin refactoring layer over the top of an existing Perl editor. For various reasons, I couldn't make this workable.</p><p>To my great surprise and astonishment, the Perl Foundation decided to pay out the grant anyway. Their reasoning was that I had indeed completed all the secondary goals, and the benefits provided by the creation of Vanilla Perl (later to become Strawberry Perl) which was NOT in the grant made the grant worthwhile anyway.</p><p>As Curtis noted at the time "Given that he didn't complete his grant, some might be surprised that we've decided to make the final payment...".</p><p>And indeed, from time to time the subject has come up here and there about getting paid despite not succeeding. Not often, and not loudly, but occasionally and ongoing.</p><p>It has also eaten at me. I hate not delivering on what I say I'll do, and I wanted the refactoring editor for me as much as for everyone else. While Padre has grown and improved, it's never quite met my expectations of what a great Perl IDE should be like.</p><p>So it is with great joy that with the landing of the Task 2.0 API I think Padre finally meets the criteria that I set for myself in taking the grant, a Perl Refactoring IDE that would let me give up Ultraedit and present Perl in a modern GUI setting.</p><p>Task 2.0 makes Find In Files, Replace In Files, and Incremental Search only a small amount of coding away from being created. These are the last features I need to finally ditch Ultraedit once and for all. The time has arrived, I think, to draw a line in the sand.</p><p>And so almost 5 years after the original grant, it is with great joy that I would like to formally report I have completed my 2005 Perl Foundation grant.</p><p>I have built, on top of the shoulders of Gabor and the rest of the Padre gang, a refactoring editor that I think will fire the imagination of Perl developers.</p><p>And I hope that this corrects and draws to a close one of the most persistently annoying failures in my Perl career.</p><p>Please enjoy the features in the new Padre releases as they appear over the next month and a half, leading up to Padre's second birthday party.</p><p>I am extremely proud of what the whole Padre gang has achieved in the last year, and I can't wait to stabilise a new group of features just waiting for the background support to firm up a little more.</p> Alias 2010-06-15T12:41:57+00:00 journal The CPAN just got a whole lot heavier, and I don't know why http://use.perl.org/~Alias/journal/40387?from=rss <p>According to the latest CPANDB generation run, and the associated Top 100 website at <a href="http://ali.as/top100">http://ali.as/top100</a>, something big just happened to the CPAN dependency graph.</p><p>After staying relatively stable for a long time, with the 100th position coming in at around 145 dependencies and incrementing by 1 every 3 months, the "weight" of the entire Heavy 100 set of modules has jumped by 20 dependencies in the last week or so!</p><p>The 100th position is now sitting at 166 dependencies, and perennial leader of the Heavy 100 MojoMojo has skyrocketed to an astonishing 330 dependencies. The shape of the "Jifty Plateau" is also much less distinguishable, which suggests it might be more than just a pure +20 across the board.</p><p>The question is why?</p><p>Is this caused by the restoration of a broken META.yml uncovering formerly ignored dependencies? Or has someone added a new dependency somewhere important accidentally?</p> Alias 2010-06-09T05:49:49+00:00 journal Padre::Task 2.0 - Making Wx + Perl threading suck faster http://use.perl.org/~Alias/journal/40377?from=rss <p>Some time <i>Real Soon Now</i>, I'll be landing the shiny new second-generation Padre Task API (which is used for background tasks and threading control) onto trunk.</p><p>A few people have asked me to give a quick high level overview on how it works, so this will be a quick bottom to top pass over how Padre will be doing threading.</p><p>The first-generation <a href="http://search.cpan.org/perldoc?Padre::Task">Padre::Task</a> API was true frontier programming. While some of us knew <a href="http://search.cpan.org/perldoc?Wx">Wx</a> and others knew Perl's <a href="http://search.cpan.org/perldoc?threads">threads</a> a bit, nobody really had any idea how the two interact. Indeed, the proliferation of bugs we found suggests that <a href="http://search.cpan.org/perldoc?Padre">Padre</a> has really been the first major application to use both at the same time.</p><p><a href="http://search.cpan.org/~smueller/">Steffen M&#252;ller</a> boldly led the Padre team into this wilderness, putting together a solid threading core loosely inspired by the <a href="http://search.cpan.org/perldoc?Process">Process</a> API. He nursed a ton of bug reports and tracked upstream fixes in Wx.pm.</p><p>Some of the code was a bit ugly in places, and the threads burned a ton of memory, but it worked and worked well. It worked well enough that <a href="http://search.cpan.org/~bramble/">Andrew Bramble</a> was later able to extend it to add Service support for long running background tasks with bidirectional communication.</p><p>But while we've reduced some of the worst of the memory problems with the "slave driver" methodology, the API has been at the end of its natural life for a while now. It's hard to write new background tasks without knowing both Wx and threads, which limited access to only three or four people.</p><p>The goals for the new Padre::Task 2.0 are threefold.</p><p>Firstly, to allow the creation of the three distinct background jobs we need in Padre, in a way that doesn't abuse either Wx or Perl's threads mechanism. These three background job types are Task (Request,Wait,Response), Stream (Request,Output,...,Response) and Service (Request,Input,Output,...,Response).</p><p>Second, to allow the implementation to have (or have in the future) the theoretically smallest possible memory consumption beyond the minimum overheads imposed by Perl's threading model.</p><p>Third, to allow the creation of Wx + threads tasks without the need to learn either Wx or threads. This should open up background tasks to the main body of Padre contributors, beyond the elites, and spur great improvements in Padre's ability to take full advantage of multi-core developer machines.</p><p>A fourth bonus goal is to allow us to migrate Padre's backgrounding implementation to something other than threads in the future, without having to change any of the code in the actual tasks next time around. This should also allow the people that don't like Perl threads and want us to use something else to move their arguments from bikeshedding to actual proof-by-code.</p><p>After several months of experimenting, I've gone with a somewhat unusual implementation, but one that is completely workable and meets the criteria.</p><p>The core of this implementation is a communications loop that allows messages from the parent thread to a child thread, and back again.</p><p>The odd thing about this particular communications loop is that the two halves of the loop are done using utterly different underlying mechanisms.</p><p>The parent --&gt; child link is done using Perl threads shared variables, in particular Thread::Queue.</p><p>Each Padre thread is created via a a Padre::TaskThread parent abstraction, which governs the creation of the real threads.pm thread, but also provides a <a href="http://search.cpan.org/perldoc?Thread::Queue">Thread::Queue</a> "inbox" for each thread. This is inspired by the Erlang micro-threading model for message passing, but is way way heavier.</p><p>In this manner, the top level task manager can keep hold of just the queue object if it wants, feeding messages into the queue to be extracted at some unknown place in another thread it has no control over.</p><p>Once spawned, each worker thread immediately goes into a run-loop waiting on messages from its message queue. Messages are simply RPC invocations, with the message name being a method name, and the message payload becoming method parameters.</p><p>Every thread has the ability to clone itself if passed an empty Padre::TaskThread object to host it. This gets a little weird (you end up passing shared Thread::Queue objects as a payload inside of other shared Thread::Queue objects) but the end result is that you don't have to spawn Perl threads from the parent thread, you can spawn them from child threads but retain the parent's ability to send messages to them regardless of the location on the thread spawn graph they are actually running.</p><p>The end result of this trickery is that we can replicate the slave driver trick from the first-generation API. By spawning off an initial pristine thread very early in the process, when the memory cost is small, we can create new threads later by spawning them off this "master" thread and retain the original low per-thread memory cost.</p><p>And while we don't do it yet, we can be even tricksier if we want. If we have a thread that has had to load 5, 10, or 20 meg of extra modules, we don't need to load them again. Instead, we could choose to clone that child directly and have a new thread with all the same task modules pre-loaded for us.</p><p>The second half of this communications loop is the up-channel, which is done using a totally different Wx mechanism. For communicating messages up to the parent, the Wx documentation recommends the creation of different messages types for each message, and then the use of a thread event.</p><p>This care and feeding of Wx turns out to be difficult in practice for non-elites, because you end up registering a ton of different Wx event types, all of which need to be stored in Perl thread-shared variables. And each message needs to be pushed through some target object, and the choice of these can be difficult.</p><p>Instead, what we do instead is to register a single event type, and a single global event "conduit". As each message is received by the conduit, it filters down to just appropriately enveloped events and pass only those along to the task manager. The task manager removes the destination header and routes it to the correct task handle in the parent.</p><p>Again, messages are done as RPC style calls, with a message type being the method to call, and the payload being the params.</p><p>This lets you do a reasonable simple form of cross-thread message passing (at least from the child to the parent anyway).</p><blockquote><div><p> <tt>sub in_child {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; $self-&gt;message('in_parent', 'Some status value');<br>}<br> &nbsp; <br>sub in_parent {<br>&nbsp; &nbsp; my $self&nbsp; &nbsp;= shift;<br>&nbsp; &nbsp; my $status = shift;<br>}</tt></p></div> </blockquote><p>We've also put a Padre::ThreadHandle layer over the task itself to do eval'ing and other cleanliness work, in the same way we put a Padre::PluginHandle over every plugin object to protect us against them.</p><p>This handle adds some extra value as well, automatically notifying the task manager when a task has started and stopped, and generally keeping everyone sane.</p><p>Within this communications loop lives the actual tasks.</p><p>The Task API forces work into a very rigid structure. The rigid rules on behaviour is the cost of allowing all the threading magic to happen without the task having to know how it happens.</p><p>The basic API looks something like this.</p><blockquote><div><p> <tt>package Some::Task;<br> &nbsp; <br>use strict;<br>use base 'Padre::Task';<br> &nbsp; <br># Constructor, happens in the parent at an arbitrary time before the job is run.<br>sub new {<br>&nbsp; &nbsp; my $class = shift;<br>&nbsp; &nbsp; my $self&nbsp; = bless { @_ }, $class;<br>&nbsp; &nbsp; return $self;<br>}<br> &nbsp; <br># Get ready to serialize, happens in the parent immediately before being sent<br># to the thread for execution.<br># Returns true to continue the execution.<br># Returns false to abort the execution.<br>sub prepare {<br>&nbsp; &nbsp; return 1;<br>}<br> &nbsp; <br># Execute the task, happens in the child thread and is allowed to block.<br># Any output data should be stored in the task.<br>sub run {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; require Big::Module;<br>&nbsp; &nbsp; $self-&gt;{output} = Big::Module::something($self-&gt;{input});<br>&nbsp; &nbsp; return 1;<br>}<br> &nbsp; <br># Tell the application to handle the output, runs in the parent thread after<br># the execution is completed.<br>sub finish {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; Padre::Current-&gt;main-&gt;widget-&gt;refresh_response( $self-&gt;{output} );<br>&nbsp; &nbsp; return 1;<br>}</tt></p></div> </blockquote><p>To fire off this task, in the widget which commissioned this background work you just do something like this.</p><blockquote><div><p> <tt>sub refresh {<br>&nbsp; &nbsp; my $self = shift;<br> &nbsp; <br>&nbsp; &nbsp; require Some::Task;<br>&nbsp; &nbsp; Some::Task-&gt;new(<br>&nbsp; &nbsp; &nbsp; &nbsp; input =&gt; 'some value',<br>&nbsp; &nbsp; )-&gt;schedule;<br>}<br> &nbsp; <br>sub refresh_response {<br>&nbsp; &nbsp; my $self&nbsp; &nbsp;= shift;<br>&nbsp; &nbsp; my $output = shift;<br> &nbsp; <br>&nbsp; &nbsp; $self-&gt;wx_thingy-&gt;SetValue($output);<br>}</tt></p></div> </blockquote><p>As you can see here, at no point do you need to care about threads, or event handling, or that kind of thing. You wrap a task class around the blocking part of your app, have the finish push the answer through to your wx component, and then handle it in the wx component.</p><p>Of course, this is still a little fidgety. So I'm currently in the process of adding a secondary layer for the common case where the task is created primarily for the purpose of a single parent owner.</p><p>The new API layer simplifies things even more. The task takes an "owner" param that represents the Wx component that commissioned it. It does some weaken/refaddr based indexing magic to map the task to the owner object, and then makes sure there is a default finish method to route the answer automatically back to the owner.</p><p>The neat part about this is that it takes care of synchronisation problems automatically. If the task finish is called at a time when the Wx component has been destroyed, the answer is automatically dropped and ignored.</p><p>The owner can also explicitly declare that the answers from any tasks currently in flight are no longer relevant, and those will be dropped as well.</p><p>With the new helper code, your task is shrunk to the following.</p><blockquote><div><p> <tt>package Some::Task;<br> &nbsp; <br>use strict;<br>use base 'Padre::Task';<br> &nbsp; <br>sub run {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; require Big::Module;<br>&nbsp; &nbsp; $self-&gt;{output} = Big::Module::something($self-&gt;{input});<br>&nbsp; &nbsp; return 1;<br>}<br> &nbsp; <br>1;</tt></p></div> </blockquote><p>And the code in the owner component is just this...</p><blockquote><div><p> <tt>sub refresh {<br>&nbsp; &nbsp; my $self = shift;<br> &nbsp; <br>&nbsp; &nbsp; # Ignore any existing in-flight tasks<br>&nbsp; &nbsp; $self-&gt;task_reset;<br> &nbsp; <br>&nbsp; &nbsp; # Kick off the new task<br>&nbsp; &nbsp; $self-&gt;task_request(<br>&nbsp; &nbsp; &nbsp; &nbsp; task&nbsp; =&gt; 'Some::Task',<br>&nbsp; &nbsp; &nbsp; &nbsp; input =&gt; 'some value',<br>&nbsp; &nbsp; );<br>}<br> &nbsp; <br>sub task_response {<br>&nbsp; &nbsp; my $self&nbsp; &nbsp;= shift;<br>&nbsp; &nbsp; my $task&nbsp; &nbsp;= shift;<br>&nbsp; &nbsp; my $output = $task-&gt;{output} or return;<br>&nbsp; &nbsp; $self-&gt;wx_thingy-&gt;SetValue($output);<br>}</tt></p></div> </blockquote><p>This is not the 100% final API look and feel, but it demonstrates the volume of code that you will need to write to do something in the background in the Task 2.0 API.</p><p>There's also some interesting opportunities to make it smaller again for very simple cases, by using the generic eval task to inline the execution code.</p><blockquote><div><p> <tt>sub refresh {<br>&nbsp; &nbsp; my $self = shift;<br> &nbsp; <br>&nbsp; &nbsp; # Ignore any existing in-flight tasks<br>&nbsp; &nbsp; $self-&gt;task_reset;<br> &nbsp; <br>&nbsp; &nbsp; # Kick off the new task<br>&nbsp; &nbsp; $self-&gt;task_request(<br>&nbsp; &nbsp; &nbsp; &nbsp; task&nbsp; =&gt; 'Padre::Task::Eval',<br>&nbsp; &nbsp; &nbsp; &nbsp; input =&gt; 'some value',<br>&nbsp; &nbsp; &nbsp; &nbsp; run&nbsp; &nbsp;=&gt; &lt;&lt;'END_TASK',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; require Big::Module;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $self-&gt;{output} = Big::Module::something($self-&gt;{input});<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 1;<br>END_TASK<br>&nbsp; &nbsp; );<br>}<br> &nbsp; <br>sub task_response {<br>&nbsp; &nbsp; my $self&nbsp; &nbsp;= shift;<br>&nbsp; &nbsp; my $task&nbsp; &nbsp;= shift;<br>&nbsp; &nbsp; my $output = $task-&gt;{output} or return;<br>&nbsp; &nbsp; $self-&gt;wx_thingy-&gt;SetValue($output);<br>}</tt></p></div> </blockquote><p>This would mean we don't need a task class at all, which could be useful in cases where we want to avoid generating lots of tiny 10 line task classes,<br>or where we want to generate the background code on the fly at run-time.</p><p>The downside would be that because the work is bunched inside a single task class, we lose the chance to do worker thread specialisation (where the workers track which tasks they have loaded into memory, so further tasks of the same type can be assigned to them in preference to other threads).</p><p>Perhaps we support all the different ways, so that we can pick and choose which option is best on a case by case basis and change them over time. That would certainly fit the Padre rule of "something is better than nothing, don't worry too much about having to break it later".</p><p>The downside of this approach, of course, is that breakage. The new Task API will basically kill any plugin currently doing their own background tasks.</p><p>The upside, of course, is that once they are fixed these plugins can do those background tasks much more efficiently that before.</p><p>The new Task 2.0 API will land in Padre 0.65, which should be out in about 2 weeks.</p> Alias 2010-06-03T03:37:29+00:00 journal Aspect 0.90 - Aspect-Oriented Programming for Perl, rebooted http://use.perl.org/~Alias/journal/40368?from=rss <p>After two years of development at $work, we've finally completed our program of stability work. To the great credit of our 7 man Perl team, we've managed to reduce the (predicted and actual) downtime to about 1 hour per year for our billion dollar ecommerce site that you've never heard of.</p><p>With stability solved, our focus now turns to usability. And unlike downtime, which is easily measurable, we don't really have any decent metrics for usability. So in preparation for this massive new metrics development push, for about a year now I've been hacking away on <a href="http://search.cpan.org/perldoc?Aspect">Aspect.pm</a>, Perl's Aspect-Oriented Programming framework.</p><p>My plan is to use this to write performance and metrics plugins for a generic Telemetry system, which would less us turn on and off metrics capturing for a library of different events, driven by configuration on the production hosts.</p><p>If you have never encountered Aspect-Oriented Programming before, you can think of it as a kind of <a href="http://search.cpan.org/perldoc?Hook::LexWrap">Hook::LexWrap</a> on steroids. The core "weaving" engine controls the selection and subjugation of functions, and the generation of the hooking code, and then two separate sugar-enhanced mechanisms are provided on top of this core to define what functions to hijack, and what to do when something we hit one of them.</p><p>The main power of AOP is in the ability to build up rich and complex hijacking conditions, and then write replacement code in a way that doesn't have to care about what is being hijacked and when.</p><p>This ability to manipulate large numbers of functions at once makes it a great tool for implementing "cross-cutting concerns" such as logging, tracing, performance metrics, and other kinds of functions that would normally result in having a bucketload of single lines scattered all through your implementation.</p><p>It also lets you do semi-evil "monkey-patching" tricks in a highly controlled manner, and potentially limited to only one single execution of one single process, without having to touch the target modules all the time everywhere.</p><p>For example, the following code shortcuts to false a particular named function only if it isn't being called recursively, and randomly for 1% of all calls, simulating an intermittent failure in the interface to some kind of known-unreliable hardware interface like a GPS unit.</p><blockquote><div><p> <tt>use Aspect;<br> &nbsp; <br>before {<br>&nbsp; &nbsp; $_-&gt;return_value(undef);<br>} call 'Target::function' &amp; highest &amp; if_true { rand() &lt; 0.01 };</tt></p></div> </blockquote><p>While the original implementation of Aspect.pm wasn't too bad and did work properly, it had two major flaws that I've been working to address.</p><p>Firstly, it was trying to align itself too closely to the feature set of AspectJ. Unlike AspectJ, which does aspect weaving (installation) at compile time directly into the JVM opcodes, Perl's Aspect.pm does weaving at run-time using function-replacement technique identical to Hook::Lexwrap.</p><p>This difference means there's certain techniques that AspectJ does that we can't really ever do properly, but there are other options open to us that couldn't be implemented in Java like the use of closures.</p><p>For example, with Aspect.pm you can do run-time tricks like that rand() call shown above. Since the if_true pointcut is also a closure, you can even reach have it interact with lexical variables from when it was defined.</p><p>This makes for some very interesting options in your test code, allowing lighter alternatives to mock objects when you only want to mock a limited number of methods, because you can just hijack the native classes rather than building a whole set of mock classes and convincing your main code to make use of them.</p><blockquote><div><p> <tt>use Aspect;<br> &nbsp; <br># Hijack the first four calls to any foo_* method<br>my @values = qw{ one two three four };<br>before {<br>&nbsp; &nbsp; $_-&gt;return_value(shift @values);<br>} call qr/^Target::foo_\w+$/ &amp; if_true { scalar @values };</tt></p></div> </blockquote><p>The second problem I've fixed is the speed. The original implementation made heavy use of object-orientation at both weave-time and run-time.</p><p>Logically this is a completely defensible decision. However, from a practical standpoint when you are going to be running something inline during function calls, you don't really want to have to run a whole bunch of much more expensive recursive methods.</p><p>So I've restructured much of the internals to greatly improve the speed.</p><p>I've dumbed down the inheritance structure a bit to inline certain hot calls at the cost of a bit more code.</p><p>I've also implemented a currying mechanism, so that run-time checks can safely ignore conditions that will always be true due to the set of functions that ended up being hooked.</p><p>And finally, rather than do method calls on the pointcut tree directly, we now compile the pointcuts down to either a string parameter-free equivalent functions.</p><p>In the ideal case the entire pointcut tree is now expressed as a single-statement Perl expression which makes no further function calls at all.</p><p>This not only removes the very expensive cost of Perl's function calls, but having everything in a single expression also exposes the boolean logic to the lower-level opcode compiler and allows culling and shortcutting at a much lower level.</p><p>With these two major improvements in place, I've also taken the opportunity to expand out the set of available conditions to include a number of additional rules or interest to Perl people that don't have equivalents in the Java world like tests for the wantarray'ness of the call.</p><blockquote><div><p> <tt>use Aspect;<br> &nbsp; <br># Trap calls to a function we know behaves badly in list or void contexts<br>before {<br>&nbsp; &nbsp; $_-&gt;exception("Dangerous use of function in non-scalar context");<br>} call 'Target::function' &amp; ! wantscalar;</tt></p></div> </blockquote><p>In addition to the expanded functionality, I've also massively expanded the test suite and written up full (or at least nearly full) POD for all classes in the entire Aspect distribution.</p><p>To celebrate this near-completion of the first major rewrite phase, I've promoted the version to a beta'ish 0.90.</p><p>There's still some work to do before release 1.00. In particular, at present the point context objects still work to a single unified set of method calls, regardless of the advice type.</p><p>This means that advice code can attempt to interrogate or manipulate things that are irrelevate or outright illegal in certain contexts.</p><p>Cleaning this up will elevate these bad context usages to "method not found" exceptions, and will also allow prohibiting the use of pointcut conditions in contexts where they are meaningless (such as exception "throwing" clauses for before { } advice when no such exception can exist).</p><p>It should also allow faster implementations of the point context code, because it won't need to take multiple situations into account and can specialise for each case.</p><p>Once this is completed, and some additional test scripts have been adding for particularly nasty cases, I'll be able to do the final 1.00 release.</p> Alias 2010-05-27T02:44:01+00:00 journal Add safety to test scripts for File::HomeDir applications http://use.perl.org/~Alias/journal/40363?from=rss <p>I always feel a bit depressed when I go on a long geek/coding trip and don't come back having released something.</p><p>Since my work is slowly drifting more towards architecture and strategy where I do less coding than I used to, writing something this trip has been tough.</p><p>Fortunately, with a few hours to kill at Seattle airport I've managed to knock out File::HomeDir::Test, which is a way to test applications that use File::HomeDir safely and without spewing files into places that the installed application will discover later.</p><p>The pattern in your application is just the following...</p><blockquote><div><p> <tt>use File::HomeDir::Test;<br>use File::HomeDir;</tt></p></div> </blockquote><p>The first line creates a temporary directory that lives for the duration of the test scripts, ads hijacking flags for the base File::HomeDir load, and hijacks $ENV{HOME} to point to the temp directory.</p><p>After you have loaded File::HomeDir::Test (in a way that results in -&gt;import being called) File::HomeDir should just work as normal.</p><p>It has been released as File::HomeDir 0.91. This release also sees the landing of the FreeDesktop.org driver in a production release for the first time, so please report any problems you may see on Linux.</p> Alias 2010-05-23T23:58:26+00:00 journal Quote of the Week http://use.perl.org/~Alias/journal/40358?from=rss <p>With apologies for any paraphrasing from my flawed memory.</p><p>"My god, you guys actually get it. I need to take some Perl people to every meeting I have, because nobody else seems to understand the importance of designing for back-compatibility properly."</p><p>-- Rob Mensching (The creator of Windows Installer XML and the WiX toolkit, the first open source project ever at Microsoft).</p> Alias 2010-05-20T17:57:09+00:00 journal Frugal Innovation - The Economist discovers ::Tiny http://use.perl.org/~Alias/journal/40343?from=rss <p>In the April 15th edition of The Economist, they provide a special report on innovation in emerging markets.</p><p><a href="http://www.economist.com/specialreports/displaystory.cfm?story_id=15879359">http://www.economist.com/specialreports/displaystory.cfm?story_id=15879359</a></p><p>Half of the report focuses on what is essentially a restatement of the principles behind<nobr> <wbr></nobr>::Tiny, but for real world products rather than software.</p><p>They term this "Frugal Innovation", and it involves taking types of devices consumed by the rich world, and then reinventing the idea behind them to make entirely new and novel devices (NOT just simple copies) that achieve the same or most of the same effect but for much less.</p><p>They trumpet the same magic formula that<nobr> <wbr></nobr>::Tiny uses, which is to provide a similar but effective function at a 90% reduction in cost, compared to existing products that have evolved via "Fat Innovation" (the typical rich world innovation which results in having new models every year, with more features and more complexity).</p><p>Frugal Innovation doesn't just involve reducing the input and overhead costs, but sometimes reinventing the process used to create the software. And ruthlessly stripping out anything that isn't universally necessary.</p><p>Some of the same principles are now also being applied to services, with one Indian medical centre setting up essentially a production line for heart operation, applying the same principles of specialisation and copious less skilled support services that created Ford's original production lines for products.</p><p>There's a great podcast from The Economist on the same topic here...</p><p><a href="http://feedproxy.google.com/~r/economist/audio_all/~3/e078AnUezYE/20100416_sr_innovations_4EQO.mp3">http://feedproxy.google.com/~r/economist/audio_all/~3/e078AnUezYE/20100416_sr_i<nobr>n<wbr></nobr> novations_4EQO.mp3</a></p><p>One interesting side note is that for software this same principle appears to feed into the measure of long term evolution I've mentioned in a couple of my talks, which is "Information processed, per unit space, per time".</p><p>This might be something that's actually interesting to measure in it's own right. You could measure this "Software Density" score by taking the amount of work some code does, and then look at how much code is never (or rarely) run.</p><p>This would be something similar to coverage testing, but for regular operation.</p> Alias 2010-05-04T02:08:57+00:00 journal I will be in the US from the 12th to the 23rd of May http://use.perl.org/~Alias/journal/40335?from=rss <p>On the 13th and 14th of May I will be in Redmond, Washington at the 2 day kick off workshop for Microsoft-funded "Common Opensource Application Publishing Platform".</p><p>CoApp is an attempt to replicate something similar to Debian's dpkg/apt within the native Microsoft MSI installer, a single standard dependency and packaging system for install the large and complex dependency trees that exist in Open Source software.</p><p>While I don't have any official role in the project, I'll be providing advice wearing a mix of Perl toolchain, <a href="http://cpan.org/">CPAN</a>, <a href="http://strawberryperl.com/">Strawberry</a>, <a href="http://openjsan.org/">OpenJSAN</a> and <a href="http://ccan.ozlabs.org/">CCAN</a> hats.</p><p>I'm also hoping to firm up the fairly obvious idea of building a binary package repository for Strawberry Perl similar to ActiveState's PPM repository, except one which would be based on native MSI packages and would support the concept of cross-language dependencies into C library space (reliable installation of shared common libfoo.dll libraries are the initial primary target of the CoApp project).</p><p>Strawberry has never had this binary package repository primarily because it hasn't made a lot of sense to put in the enormous programming and computational effort when we can't actually provide anything better than ActiveState's system (it's better that we just leverage off it).</p><p>CoApp represents a new model for binary packages that has the potential to be significantly better than PPM, and so it's a much more interesting option to explore.</p><p>I'll also be in Framingham (near Boston) from the 17th to the 22nd of May at the Staples HQ (who are buying up the company I work at) doing some exploratory meetings to meet my counterparts in the US and look for interesting technology to steal and bring back to the Australian office.</p><p>Between and around these dates I should have some day trip and evening catchup opportunities with Perl folks. I'd also be quite happy to do any talks for local Perl monger groups if we can organise transport and a projector somewhere.</p><p>This trip is at short notice and my schedule is still firming up, but if you are interesting in doing something, mail me on my adamk@cpan address and let me know.</p> Alias 2010-04-30T01:16:05+00:00 journal Mojo vs Dancer Week 2 - Templates and Images http://use.perl.org/~Alias/journal/40312?from=rss <p>Welcome back.</p><p>My apologies for the delay. I blame trying to keep up with the QA hackathon from half a world away, and another <a href="http://www.youtube.com/watch?v=gDSRdp6Ar3M">unavoidable event from which I could not escape</a>.</p><p>I've also delayed another day because I'm a bit concerned that my review this week would paint Mojo in an unfair light, and I wanted to sleep on it.</p><p>As I get deeper into both, I'm finding that many things I don't like about one turns out to have a similar behaviour in the other. As a result, whichever one I review first would be the one that a stream of consciousness commentary will paint in a worse light.</p><p>And I've wanted to start each week with Mojo first, as the more established competitor. But I think this might be unfair given the emerging similarities.</p><p>So each week I will reverse the order I review them in, and this week I shall attempt to emulate finding my annoyances in Dancer first<nobr> <wbr></nobr>:)</p><p>This week, I had originally planned to look at configuration and database.</p><p>Like in many projects though, this turned out to be way too trivial because I'm basing the website on the <a href="http://search.cpan.org/perldoc?CPANDB">CPANDB</a> module, which is zero-configuration.</p><p>So in BOTH applications, I only had to add the following and I have my database layer finished<nobr> <wbr></nobr>:)</p><blockquote><div><p> <tt>use CPANDB {<br>&nbsp; # Don't check for updates more than once a day<br>&nbsp; maxage =&gt; 86400,<br>};</tt></p></div> </blockquote><p>Instead, I'm going to look at the second phase for most website projects as a newbie. Bootstrapping from helloworld.pl into an equivalent "proper" website with templates, images and CSS, but no actual content.</p><p><b>Dancer - Bootstrapping a website</b></p><p>Since my review last week, a couple of new releases of Dancer hit the CPAN claiming to fix installation on Win32. Just to prove it, I've done this week's testing on my conference presentation laptop instead of my desktop machine.</p><p>Dancer installed first time cleanly on the new machine. And the hello world script from last week runs correctly. So all good there.</p><p>After a more-complete-than-last-week read through the main Dancer search.cpan.org page one thing jumps out quite sharply about the Dancer API in general. And this is that it isn't object-oriented, which is something or a rare thing these days.</p><p>Or at least, it doesn't LOOK object-oriented. Judging from the distribution page there's plenty of classes and I'm sure the internals are all done largely in an OO fashion.</p><p>The main API that you get with "use Dancer" sports a similar kind of "Do What I Mean" command interface that reminds me a bit of the Module::Install command interface.</p><p>This means that the code to show the index template is going to look like this.</p><blockquote><div><p> <tt>get '/' =&gt; sub {<br>&nbsp; &nbsp; template 'index';<br>};</tt></p></div> </blockquote><p>I'm not entirely sure what I think about this idea, despite the fact that I'm the maintainer of M:I and created it's Domain Specific Language inteface. This kind of thing usually raises red flags.</p><p>I can see this API strategy either descending into API chaos or becoming one of Dancer's best and most loved features. Or quite possibly both depending on the scale of the project.</p><p>For the moment, given Dancer is meant to be taking a micro-framework approach (which should be optimised more for small websites) I'm willing to suspend my disbelief and run with it until I can make a better judgement.</p><p>The documentation in general is oddly structured. For a command-oriented API like this I would expect to find documentation for each of the available commands. This section of the documentation does exist, but it doesn't contain a list of all the commands.</p><p>Instead, some of the commands are described down in sub-headings related to a logical area instead. And if you look at the table of contents on the search.cpan page the logical grouping doesn't appear very, well, logical.</p><p>There's some other indications the documentation has built up in bits and pieces rather than being addressed in a complete fashion. Some features are glossed over quickly, leaving me a bit stumped still. Other go into way more detail than is needed for a small website to the point of information overload.</p><p>The section on config files seems to suggest I should make three config files, a global config and then a pair of development/production config files that overlay the global. And these files go in different directories for some reason, unless I "put it all at the top of the program" (without saying how I embed this YAML in the program). A bit later on I realised they meant embed via the "set" command.</p><p>Overall, I think the documentation is reasonably thorough but just needs some love to clean it up into a more learning-friendly structure, with some sections shrunk down in the main Dancer page to just the most basic and common uses and references out to other pages for using more advanced features.</p><p>Stuck on something I wasn't sure about, I resorted to running the built in skeleton generator (mentioned prominently on the Dancer::Cookbook page) to at least get a better idea of what I was supposed to be doing.</p><blockquote><div><p> <tt>C:\Users\Adam&gt;dancer -a top100<br>+ top100<br>+ top100\views<br>+ top100\views\index.tt<br>+ top100\views\layouts<br>+ top100\views\layouts\main.tt<br>+ top100\environments<br>+ top100\environments\development.yml<br>+ top100\environments\production.yml<br>+ top100\config.yml<br>+ top100\app.psgi<br>+ top100\public<br>+ top100\public\css<br>+ top100\public\css\style.css<br>+ top100\public\css\error.css<br>+ top100\public\images<br>+ top100\public\404.html<br>+ top100\public\dispatch.fcgi<br>+ top100\public\dispatch.cgi<br>+ top100\public\500.html<br>+ top100\top100.pm<br>+ top100\top100.pl</tt></p></div> </blockquote><p>For a few seconds this shocked me, because compared to the simplicity of helloworld.pl this is a lot more files.</p><p>At this point I hadn't even remotely considered the idea of site-customising my error pages, and there's 5 entirely different types of Perl application files in this list. I (newbie me) don't even know what PSGI is, let alone why I need one. And don't get why I have a dispatch.cgi in addition to my top100.pl script.</p><p>Frankly, I don't even really WANT to know what all these things are (yet?). But this did at least confirm where all the files should be living and the demo app did actually start and run properly. So in my case, it solved the problem I needed to solve.</p><p>But I certainly don't want to use it as the basis of my Top 100 site. It's just a bit overwhelming for my level of experience, and I don't want to have to go exploring and work out what all these different files do, so I know which ones are safe to delete.</p><p>I'm not ready yet, I have an index page to get showing first.</p><p>Templating was largely straight forward, mostly because the docs do everything to steer me towards Template Toolkit short of installing it for me (yes, you have to install Template Toolkit yourself to get the generated skeleton website working).</p><p>I suspect the reason for this is because their embedded default templates are not PARTICULARLY featured. The documentation sums up the feature set of the built in templates as the following.</p><blockquote><div><p> <tt>&lt;% var1 %&gt;</tt></p></div> </blockquote><p>No other features are described, making Template Toolkit the obvious choice.<nobr> <wbr></nobr>:)</p><p>I'm totally fine with this, but what I'm not entirely sure about is why on earth they have chosen to make Dancer's default tag style for Template Toolkit different to Template Toolkit's default tag style for Template Toolkit.</p><p>The only reason I could uncover from the documentation is that it makes TT compatible with their built in template engine. The one whose list of features is "variables".</p><p>The only other guess other than "we like it more that way" I can make are that it's done to be compatible with Sinatra, the Ruby toolkit I've never heard of but which I'm told was the inspiration for Dancer.</p><p>Switching it back to regular Template Toolkit tag style requires a slightly annoying block of config file entries I can easily imagine myself repeating in every Dancer program I will ever write.</p><p>To help you in gauging my annoyance level on this topic, allow me to show you now the complete working Dancer application at the end of this week.</p><blockquote><div><p> <tt>#!/usr/bin/perl<br> &nbsp; <br>use Dancer;<br>use Template;<br>use CPANDB {<br>&nbsp; &nbsp; maxage =&gt; 3600 * 24 * 7,<br>};<br> &nbsp; <br># Configuration block<br>set template =&gt; 'template_toolkit';<br>set engines&nbsp; =&gt; {<br>&nbsp; &nbsp; template_toolkit =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; start_tag =&gt; '[%',<br>&nbsp; &nbsp; &nbsp; &nbsp; stop_tag&nbsp; =&gt; '%]',<br>&nbsp; &nbsp; },<br>};<br> &nbsp; <br># Route block<br>get '/' =&gt; sub {<br>&nbsp; &nbsp; template 'index';<br>};<br> &nbsp; <br>dance;</tt></p></div> </blockquote><p>It's not a problem as such, but I'm sure it's one of those things that's going to niggle at me. If I wasn't trying to emulate a newbie, I'd probably switch over to the Template::Tiny plugin in the short term. Unfortunately, it's not particularly well known and so is probably out of bounds for this competition.</p><p>Given their strong preference for Template Toolkit, in their situation I'd probably have inlined the entire Template::Tiny package as the "house template" engine. Then you still have a direct upgrade path when people hit a feature T:Tiny didn't support but you get to keep the default tag style. But the current predates Template::Tiny, and so be it.</p><p>I also had a momentary confusion over whether I should call my template "index" or "index.tt" or "index.html" or "index.html.tt", but I put that mostly down to playing with Mojo's double-dotted templates (which I'll get to later). A quick look at the generated skeleton made it pretty clear what the naming is.</p><p>Adding the static files was very simple and easy to understand, following the convention of "if there's a "public" directory, everything in it is a static file".</p><p>However, I did hit a problem when I tried to add my logo image.</p><p>Weirdly, although my Dancer application was happily sending me css and my favicon.ico file, it didn't appear to support PNG images. Bemused, I placed my first (legitimate) visit to the #dancer channel to ask a What The Hell.</p><p>Dancer uses MIME::Types under the covers, and the bug only happens on Windows, and they confirmed they can replicate it. Beyond that there's no more information yet, but I've worked around the problem temporarily on my Dancer application by converting the PNG files to GIF.</p><p>And given the speed with which they chased down the previous Windows problems, I'm hopefully that by next week the problem will have gone away.</p><p>The final issue I forsee in any future life with Dancer is the way in which the templates and the static files combine together.</p><p>Although I'm capable of writing HTML by hand, I don't like to. I've been a constant Dreamweaver user version 1.0, because you gain all the benefits of seeing your page design as you work on it but without any risk of damaging templates.</p><p>(Historical Note: Dreamweaver's "Round Trip HTML" parsing ability was the primary source of inspiration for PPI's "Round Trip Perl" parsing)</p><p>By having all the static files in<nobr> <wbr></nobr>/public and all the templates in<nobr> <wbr></nobr>/views but serving everything from root, you can't really open a template in a GUI HTML editor and have the static files be consumed by the templates.</p><p>This problem is compounded by Dancer's "layout" feature, which is sort of like an inside-out INCLUDE block. I can see the attraction for things like "skinning" websites or having lite/print rendering, but it would also make it even harder to edit content using anything other than raw HTML.</p><p>I know a lot of Perl people don't like the GUI crowd, but the newbie web crowd is really going to live and die by GUI tools (which explains the popularity of PHP really).</p><p>Overall, the process was relatively straight forward with the exception of the PNG problem and a general feel that the documentation/tools dump you in the deep end a bit too quickly and need polishing.</p><p><b>Mojo - Bootstrapping a website</b></p><p>Having looked a little deeper into both Mojo and Dancer, one thing that strikes me is the level of similarity between the two. I'm assuming that there's a fair bit of feature and convention theft going on between the two, and thus presumably Ruby Sinatra as well.</p><p>In particular, Mojo also uses a separate<nobr> <wbr></nobr>/public and<nobr> <wbr></nobr>/templates directories and the documentation prominently mentions layout support. So the problem of templates that can't be edited in a WYSIWYG fashion also applies to Mojo.</p><p>In fact, having seen both doing this I can't help but wonder if this is part of the cause of the simplicity and/or stagnation I see on both websites.</p><p>When all site modifications have to be done in the raw, it makes it harder for casual contributors to provide ad-hoc content or look-and-feel improvements to the site.</p><p>The main Mojolicious::Lite isn't bad but it's rather short on written commentary and chock full of examples, with no separation into topics of sub-heading.</p><p>It comes across as a sort of giant SYNOPSIS, and I would have appreciated a bit more information beyond example code.</p><p>The curious file naming of templates in Mojo comes in for specific attention here. Template files use an interesting double-extension mechanism. Templates are referred to by their base name in code, and then the extensions indicate content type and template format respectively.</p><p>The most awesome thing that emerges from this is the idea that Mojo can use the same identical code to support multiple different content type requests. From the Mojo mega-SYNOPSIS docs.</p><blockquote><div><p> <tt>#<nobr> <wbr></nobr>/detection.html<br>#<nobr> <wbr></nobr>/detection.txt<br>get '/detection' =&gt; sub {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; $self-&gt;render('detected');<br>};<br> &nbsp; <br>__DATA__<br> &nbsp; <br>@@ detected.html.ep<br>&lt;!doctype html&gt;&lt;html&gt;<br>&nbsp; &nbsp; &lt;head&gt;&lt;title&gt;Detected!&lt;/title&gt;&lt;/head&gt;<br>&nbsp; &nbsp; &lt;body&gt;HTML was detected.&lt;/body&gt;<br>&lt;/html&gt;<br> &nbsp; <br>@@ detected.txt.ep<br>TXT was detected.</tt></p></div> </blockquote><p>The flexible option of either embedded or standalone template files is also very cool for allowing complete websites in live in a single file.</p><p>As a bonus challenge to push out this potentially legendary flexibility, I decided to try and get Mojo installed and working on my Google Nexus One phone. The Android Scripting Environment comes with a trivially easy ability to add Perl support (5.10.1 no less), and all I had to do was drop the lib directory from the Mojo distribution onto the phone via USB, along with the Mojo helloworld.pl file.</p><p>Unfortunately, it failed the test although arguably not through any fault of it's own. The Mojo deep internals make use of the core module Encode.pm and unfortunately Android Perl does NOT come with Encode.pm in it, and making the Encode dependency optional isn't really an option for them due to the depth at which it is needed.</p><p>But back to templates.</p><p>And here's where I get negative about Mojo. While the in-house templating in Dancer is an afterthought they sweep under the rug in preference to Template Toolkit (which is almost, oddly, a positive) Mojo backs it's in-house templating 100% so it stays zero-dependency.</p><p>And the Mojo template style is really really messy. It's essentially an "embedded Perl" tag-flipping system which sees your templates HTML mixed deeply with Perl fragments.</p><p>Template features are provided via a fairly powerful Perl API in those fragments, which at least makes the best of things.</p><p>Now while I'm absolutely against mixing code and content, I do recognise that this approach might be useful in small contexts (it tends to be something that fails mostly at scale).</p><p>But what really makes me cringe is this.</p><blockquote><div><p> <tt>&lt;% Inline Perl %&gt;<br>&lt;%= Perl expression, replaced with result %&gt;<br>&lt;%== Perl expression, replaced with XML escaped result %&gt;<br>&lt;%# Comment, useful for debugging %&gt;<br>% Perl line<br>%= Perl expression line, replaced with result<br>%== Perl expression line, replaced with XML escaped result<br>%# Comment line, useful for debugging</tt></p></div> </blockquote><p>That's right, there are EIGHT different tag types. Four different ordinary tags alone would push some complexity budgets, but the real crime is the idea of duplicating those four into another four that are enhanced by significant whitespace!</p><p>These are further complicated by an optional closing modifier as seen in the following.</p><blockquote><div><p> <tt>&lt;%= All whitespace characters around this expression will be trimmed =%&gt;</tt></p></div> </blockquote><p>This introduces another disturbing idea, that of symmetrical escaping where each side means something different to the other.</p><p>And it gets even scarier once you add block capturing.</p><blockquote><div><p> <tt>&lt;%{ my $block = %&gt;<br>&nbsp; &nbsp; &lt;% my $name = shift; =%&gt;<br>&nbsp; &nbsp; Hello &lt;%= $name %&gt;.<br>&lt;%}%&gt;<br>&lt;%= $block-&gt;('Sebastian') %&gt;<br>&lt;%= $block-&gt;('Sara') %&gt;<br> &nbsp; <br>%{ my $block =<br>% my $name = shift;<br>Hello &lt;%= $name %&gt;.<br>%}<br>%= $block-&gt;('Baerbel')<br>%= $block-&gt;('Wolfgang')</tt></p></div> </blockquote><p>And for good measure, it seems to "enhance" HTML with Unix-style line continuations!</p><blockquote><div><p> <tt>This is &lt;%= 23 * 3 %&gt; a\<br>single line</tt></p></div> </blockquote><p>The sum total of all these features is to be utterly hostile to editing templates in anything other than raw text, and I have genuine fears that if I unleashed a mental list of people on these templates they would very rapidly decent into sigil soup and line noise.</p><p>If I do go with Mojo at the end of this process, it will absolutely be with the provision that under no circumstances will I allow myself to look at the full template documentation, to prevent tempting myself into using some of the features described above.</p><p>And the really sad part is I'm really not sure I actually NEED any of the features. I'm fairly certain most of the complexity could be dropped without major ill effects.</p><p>The other sad thing about all this is that once you get past the horrendous tag style, IF you can get past it, the APIs provided to the Perl code chunks have some fairly neat conveniences in them.</p><p>Each route/handler allows a name to be associated with it, which identifies the route for things like the url_for tag functions, but which also serves as a template name for the handler if that is all that is provided.</p><p>This gives Mojo far far more concise code compared to Dancer for the simple site so far. Here is the following complete Mojo code for the boostrap site.</p><blockquote><div><p> <tt>#!/usr/bin/perl<br> &nbsp; <br>use Mojolicious::Lite;<br>use CPANDB {<br>&nbsp; &nbsp; maxage =&gt; 3600 * 24 * 7,<br>};<br> &nbsp; <br>get '/' =&gt; 'index';<br> &nbsp; <br>shagadelic;</tt></p></div> </blockquote><p>Indeed, at this scale it actually IS kind of "shagadelic". But of course I don't expect the meme to hold once I've added several hundred lines of actual website functionality.</p><p><b>Week 2 Results</b></p><p><b>Best Skeleton Generator - Mojo</b></p><p>Mojo's skeleton generator offers two option, heavy and lite. This, plus the fact I found Dancer's skeleton generator to be overwhelming, give it to Mojo.</p><p>Notably though, I didn't actually end up using either of them. In both cases, it started introducing concepts I didn't really want to have to deal with so early.</p><p><b>Best Application Layout - No Winner</b></p><p>Not only are the file layouts for both frameworks pretty much identical, but both basically prevent you using GUI HTML editors. Which really sucks, so I'm not even awarding a draw. Just a FAIL.</p><p><b>Best Templating - Not Mojo</b></p><p>Even though their internal templates appear to be so thin as to be non-existant, all their documentation quickly pushes you towards Template Toolkit. As the most popular templating system (by CPAN dependency count at least) this should be familiar territory for many many people.</p><p>But I really don't want to award it to them for positive actions. This one is decided on comparative negatives.</p><p>The annoyances/gotchas of having to add the magical "act like normal TT" invocation and not making Template a proper dep when even their own site generator uses it, simply don't compare to the utter zanyness and Dreamweaver-hostility of Mojo's tag format.</p><p>So I'm awarding this one AGAINST Mojo, instead of to Dancer. Both had their own respective dissapointments.</p><p>Overall Leader after Week 2 - Mojo</p><p>Why? The thing is, even though I've been forced to read about it, I haven't actually had to really do anything in my templates yet. So there's no tangible real pain from the Mojo templating system yet. What code is there is still really really tight.</p><p>So with a balanced score this week of zero vs zero, and Dancer's dishonourable mention for the PNG bug (if only because nobody ever noticed it), Mojo remains in the lead.</p><p>Next week, I try to set up the front page to actually work and try to get a generated Top 100 list added to the site via templating.</p> Alias 2010-04-14T18:48:01+00:00 journal Competition and CPAN Errata http://use.perl.org/~Alias/journal/40309?from=rss <p>A few housekeeping issues.</p><p>1. I may be a day behind on this weekend's competition update. I've completed the Mojo half, but not the Dancer half. I'd rather post the results at the same time, so I'm delaying by one day.</p><p>2. After an email from Andreas to all CPAN authors to clean up our author directories, I've deleted about 1000 files. Unfortunately, that accidentally included all production versions of Class::Adapter, breaking Padre and a number of other things. A new 1.07 has been uploaded and this situation should be resolved shortly.</p> Alias 2010-04-11T16:26:50+00:00 journal I don't want to be forced into your damned warning policy http://use.perl.org/~Alias/journal/40302?from=rss <p><b>Update: I am informed that while I may imply a timeline which sees the pragma modules mentioned below taking action before Moose, time-wise Moose acted first and then the pragma modules came later</b></p><p>Last weekend in my first round comparison between Mojo and Dancer, I noted that neither project used strict or warnings.</p><p>At the time, I suspected this was done for clarity. After all, it can get annoying when use strict and use warnings to get in the way of having a nice a clean synopsis.</p><p>It was too my great surprise that I discovered both web frameworks had decided that use strict and use warnings were good enough for everybody and they would silently turn both of them on.</p><p>This makes them the third group of modules to decide how I should write my code.</p><p>First are your $Adjective::Perl style modules.</p><p>This I can live with and playing with pragmas seems quite reasonable, since it's a style pragma module itself. By saying "use perl5i" I'm explicitly buying into their view of what code should be written and formatted like.</p><p>Then Moose decided that they would turn on strict and warnings as well.</p><p>This makes me a bit uncomfortable, since I use Moose for it's object model. I don't really want it imposing it's views on how I should write the rest of my code.</p><p>I can hear you already saying "But wait! You can turn it off with no warnings, but you shouldn't do that because it's best practice (and Best Practice) to always have them both on, and anyway it's only enabled until you say "no Moose;"</p><p>Or is it? That alone is an interesting question.</p><p>Do Moose's views on strictness and warnings able to escape it's scope, and will be imposed on me even when I tell it to go away with no Moose;</p><p>Or if they do go away, does that mean I've accidentally been running a whole bunch of code without strict and warnings on by mistake?</p><p>But I digress, now where was I... oh right!</p><p><b>&lt;rant&gt;</b></p><p>I appreciate you are trying to be nice and save me two lines, but dammit I'm not paying you (metaphorically) for that, and now I have to THINK instead because the LACK of an option to your code can be meaningful. It's worse than meaningful whitespace, it's a meaningful unknown. And I can trivially automate the production of those "use strict;" or "use strict;\nuse warnings;" (as you prefer) lines in pretty much any hackable editor written in Perl. Automating the thinking you have to do when there ISN'T something in the code is much harder, or impossible.</p><p>This kind of thing with Exporter is one of the (four) provably impossible problems that prevent Perl being parsable. Gee thanks!</p><p>From a perception point of view it's the same kind of situation when a Media Company announces they are going to buy a Mining Company. Why? Because the Mining Company has a lot of cash but little revenue, and the Media Company has a lot of revenue but little cash, so they'd "Go well together".</p><p>Before I say any more, you should already be a bit suspicious. And it's probably no surprise when you find out that the part-owner boss of the Media Company is also a part-owner of the Mining Company.</p><p>But that kind of thing is an obvious form of Conflict Of Interest. Humans are almost universally tuned to spot that kind of thing and see it as a negative.</p><p>It's a much trickier situation when the conflict is between Doing Your Job and things like Trying To Be Nice, or things like Clearly You Probably Meant It, So I'll Just Silently Correct That For You. There's a variety of meme's in this situation, different mixed perceptions based on your own personal morality.</p><p>But that doesn't remove the technical issue that you've conflated two entirely different functions into one module.</p><p>So now with Moose if I don't want warnings, but I do want strict, I'm not sure if I need to do this...</p><blockquote><div><p> <tt>use Moose;<br>no warnings;<br> &nbsp; <br>...<br> &nbsp; <br>no Moose;</tt></p></div> </blockquote><p>or this...</p><blockquote><div><p> <tt>use Moose;<br> &nbsp; <br># Lets say I'm nice and allow all my Moose definition code<br># to follow their warnings policy, because I like their rigourous approach.<br> &nbsp; <br>no Moose;<br>use strict;<br>use warnings;</tt></p></div> </blockquote><p>Neither of these things are particularly pretty, but I'm stuck with the situation because there's a conflict of interest. The Moose authors choose to impose their views in an area outside of their scope, because it's convenient for them and saves them a couple of lines, And Besides Everyone Should Do It That Way.</p><p>But as long as it's only pragma modules that change pragmas (plus Moose) it's just an idiosyncracy, one of those weird little things modules do sometimes.</p><p>Except now we have another problem, because now It's A Trend. Everyone famous is doing it. Clearly it's The Right Thing.</p><p>So now we see web frameworks doing it. Mojo does it. Dancer does it.</p><p>Clearly it's the right thing to do, because chromatic and Schwern and Damian and the Moose cabal are doing it so it must be awesome.</p><p>At this point, you're probably preparing a snarky comment about how I'm just curmudgeonly and nit-picking. How I should only turn off warnings when I know a warnings is going to happen inside a SCOPE: { no warnings;<nobr> <wbr></nobr>... } and how we need to set a good example for the less experienced people, and how YOU always want to see the warnings in production, and how warnings create bug reports so you fix more bugs, and so on.</p><p>But what about practical issues? What about situations where you need to do big things, complicated things, large scale things in one or many of the dimensions of width, or throughput, or reliability or complexity or code size.</p><p>Over the last 10 years, in which 90% of my paid work has been on websites, I can recall three situations in which I found truly important warnings on a production web server that I didn't find in any testing, and that would have led me to a fix I otherwise would have overlooked.</p><p>I've found tons of exceptions on production sure, but not that many warnings that mattered.</p><p>However, in that same 10 years, I've seen the opposite situation 6-8 times.</p><p>I've seen sysadmins blank out a config variable the wrong way, resulting in an undef where there should have been a value, which is checked in an "eq" comparison 20 times per page, each of which produced 2-3k of log file.</p><p>Or worse, I've seen this in a foreach (<nobr> <wbr></nobr>... ) { if ( undef eq 'string' ) {<nobr> <wbr></nobr>... } } which is operating on several hundred or thousand entries.</p><p>Half the time, this happened because someone in the same office at the same time you are at work touched something they should have and uncovered it.</p><p>And when you see the load graph on the box spike the next day, you investigate and find it compressing 20gig of log files, all of which contain the same identical warning printed 40 or 50 million times.</p><p>But if you aren't so lucky, it happens on a weekend, or at night, or you haven't set something up right in Nagios, and now you've filled your machine's entire<nobr> <wbr></nobr>/var partition over the weekend, which prevented 2 or 3 other services that need<nobr> <wbr></nobr>/var too from working, which brought down the service, or the server.</p><p>I've seen 10 machine clusters running at high volume overflow every log partition in the cluster at a rate of a gig per host per minute because a telco outage at night caused a minor backend service to fail, which returned a single status string that wasn't checked for defined'ness to go undef and that status hash value was checked in the hot loop.</p><p>I've seen horrible UDP network syslog storms, and boxes dead so fast the Nagios Poll -&gt; Human Alert -&gt; Getting Online lag of 15 minutes wasn't enough to catch it and prevent it.</p><p>All of it because in a codebase of 50,000 or 100,000 lines, you only have to miss ONE thing in the wrong place to produce a warning. And nobody's perfect.</p><p>Now, by all means I encourage development with warnings on. And I absolutely think warnings should always be on in your test suite, with Test::NoWarnings enabled wherever possible for good measure, and a BEGIN { $^X = 1 } in the test header to really make sure warnings are aggressive.</p><p>If there's a configuration option for it, I'll even leave them on through User Acceptance Testing and Fuzz Testing and Penetration Testing and Load Testing and anything else that isn't Production.</p><p>In production I don't want to know about mistakes.</p><p>Well, that's not entirely true...</p><p>I want to know about mistakes in production, but what I want more is that production absolutely positively NEVER goes down. There's no debugging convenience in the world that should result in even the slight risk of turning into a Denial of Service.</p><p>The Spice MUST Flow.</p><p>If I go down in production, I want it to be for a reason that has never happened before. Ideally involve a three or four factor failure.</p><p>If a plane crashes into a telco NOC, triggering a complete network outage on my side of the city, and we switch to the disaster recovery site but the power ripples from the plane crash caused a transformer to blow, and the generator fails after 20 minutes because of a critical heat event due to a bird nest in the radiator catching on fire, because the maintenance man was on paternity 2 month paternity leave and the stand-in techie doing his job wasn't legally qualified to be on the roof with the electrical gear, THAT I can live with.</p><p>If an East European mafia takes a shining to me as a blackmail target, and initiates a 50gig/sec botnet distribution denial of service attack and we haven't set up the DDOS-protection contract because the financial crisis caused our budget to be cut this year, well that I can live with too.</p><p>If I can't afford any of that fancy stuff, but the Facebook utility my shoe-string budget startup created turns out to be too popular and despite my best efforts to keep it blazingly fast to prevent this kind of thing the success overloads my server someone just dropped the default Ubuntu on because we needed it up quickly, hey I'm happy to have that kind of problem.</p><p>Compared to these kinds of reasons for going down, having a volunteer website administrator who lives in Europe fiddle a setting they shouldn't have while I was asleep, and having the 500gig hard disk overflow with the same identical message repeated over and over 5 billion times really doesn't cut it.</p><p>And this same kind of thing seems to happen over and over again about once every 14 months, and only half the time am I lucky enough to do something about it in time.</p><p>When my object model is forcing warnings on me, and my web framework is forcing warnings on me, what am I supposed to do?</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use MyWebFramework;<br>no warnings;<br> &nbsp; <br>use Moose;<br>no warnings;<br> &nbsp; <br>use Some::Random::Module;<br>no warnings; # Can I really be sure they don't enable warnings?<br>...</tt></p></div> </blockquote><p>Am I supposed to repeat this in every single class?</p><p>What about when I want warnings ON, now what?</p><p>Unlike exceptions, it's way way harder to catch and manage warnings, to force them always on and force them always off when you are in different environments.</p><p>The only way I know of to reliable distinguish between maximum noise and diagnostics and explosions in dev/test/uat, and no noise at all in production (except properly managed exceptions) is to have the code NOT use warnings, and then force it on from the top down in the right environments.</p><p>We've seen similar things before, stuff that starts out simple and obvious but just causes pain.</p><p>The @EXPORT array was, I'm sure, just a fine idea when it was added. It lets you import whole swathes of functions into your program without that annoying typing.</p><p>Of course, since now ANYBODY can fuck with it, if you are trying to write robust code you need to do stupid annoying things like this to avoid accidentally polluting your code.</p><blockquote><div><p> <tt>use Carp&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ();<br>use Cwd&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;();<br>use File::Spec&nbsp; &nbsp; ();<br>use File::HomeDir ();<br>use List::Util&nbsp; &nbsp; ();<br>use Scalar::Util&nbsp; ();<br>use Getopt::Long&nbsp; ();<br>use YAML::Tiny&nbsp; &nbsp; ();<br>use DBI&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;();<br>use DBD::SQLite&nbsp; &nbsp;();</tt></p></div> </blockquote><p>Why do I need to do that stupid braces shit? Because the alternative is I have to audit every single dependency to make sure it doesn't export by default, and THEN I have to also trust/hope they don't start exporting by default in the future.</p><p>Loading modules the safe and scalable way means doing MORE work than the unsafe and unscalable way.</p><p>DBI gets it right. The default way of using DBI that is documented everywhere is superficially more verbose and anal retentive than I need for simple things.</p><p>But as the code gets bigger, the code keeps working just as well and just as safely. I would hypothesise that this diligence on the part of DBI and Tim Bunce has in a single stroke kept Perl web applications industry-wide almost entirely free of SQL injection attacks.</p><p>The savings in terms of just the admin workload and security spending and security-forced upgrades done on overtime on the first Tuesday of every month have probably justified Tim's entire career.</p><p>Has default-import really given us such a large benefit that it overcomes all the times people have to type () and resolved clashing imports of corrupted OO APIs? Is the time saved not having to type ':ALL' really worth all that?</p><p>I say no.</p><p>And I say that this growing nascent fad to screw around with my pragmas when your module isn't actually a pragma itself needs to be nipped in the bud before it gets worse.</p><p><b>&lt;/rant&gt;</b></p><p>While this is perhaps a controversial position (and so it won't be factored into the scoring as part of the competition) I have to say I was greatly impressed that the Dancer guys have offered to implement some kind of configuration option so I can explicitly turn disable their Dancer-imposed warnings in production (which at least mitigates the worst Real World problem, while retaining the magic pragma behaviour).</p> Alias 2010-04-08T07:58:35+00:00 journal Mojo vs Dancer Week 1 - Installer, Support and Hello World http://use.perl.org/~Alias/journal/40292?from=rss <p>Lets Get Ready To Ruuuumblllleeee*cough*splutter* ahem. Sorry about that.</p><p>Welcome to the Mojo vs Dancer Top 100 Competition.</p><p>Over the next month or so I'll be building a replacement for my prototype <a href="http://ali.as/top100">CPAN Top 100</a> website simultaneously using the Dancer and Mojolicious micro-web frameworks.</p><p><b>The Competition Rules</b></p><p>While I do have a fair bit of experience with Perl coding, I will be trying wherever possible to behave in naively and newbie'ish fashion when it comes to community, support and tools.</p><p>I hope that during this process we can get some idea of the typical end user who won't know the right people to talk to or the right places to go for help.</p><p>One round will occur each weekend. I shall address one area each round, progressing until I have a working application (hopefully two).</p><p>While each weekend you will be subjected to my newbie code, during the rest of the week I will be inviting the development teams of both web frameworks to "improve" my code. They do so, however, at risk of LOSING existing points, should they try to hard to show off and create something I don't understand.</p><p>The week gap also gives plenty of time for each team to respond to my comments, to deny problems, to clarifying mistakes, and to fix, upgrade and do new releases.</p><p>For each issue I stumble across on my journey, I shall appoint only one winner. Each week may address more than one issue.</p><p>However, while I'll be recording the scores issue by issue, ultimate victory will be based entirely on my subjective personal preference for the one I think will be quickest and easiest for me to maintain.</p><p>If you'd like to follow along at home you can checkout the code for each project at the following locations.</p><p>Mojolicious - <a href="http://svn.ali.as/cpan/trunk/Top100-Mojo">http://svn.ali.as/cpan/trunk/Top100-Mojo</a></p><p>Dancer - <a href="http://svn.ali.as/cpan/trunk/Top100-Dancer">http://svn.ali.as/cpan/trunk/Top100-Dancer</a></p><p><b>Mojo - Getting to Hello World</b></p><p>I have some history with Mojo, being present at (and in a small way contributing too) its birth when Sebastian Riedel left the Catalyst project.</p><p>I've even attempted to build a Mojo application before, but was told at the time they weren't quite ready for actual users yet.</p><p>Their website is clean, efficient, but practically unchanged since I looked at it the first time.</p><p>It's also somewhat broken or at least unmaintained. The "Blog" link just points back to the same page, the "Reference" link points at what looks like a search.cpan.org failed search, and the "Development" link just throws me out to Github (which doesn't seem to really help much if I wanted to write a plugin or something other than hacking the core).</p><p>The "Book" link points to another search.cpan error page, and the most recent version at time of writing is 0.999924 which seems weird and makes me wonder how well they run the project.</p><p>Although the website doesn't fill me with confidence, the installation process is an entirely different story. One of Mojo's core design principles is to be pure perl and have zero non-core dependencies.</p><p>Installation via the CPAN client is fast, simple, and effortless. And I have full confidence that (if I needed to) I could just drop the contents of lib into my project and upload it to shared hosting somewhere.</p><p>I hear some rumors that to achieve this they've done rewrites of some very common APIs that work slightly differently, but I won't be looking into this right now. It will be a matter for another week.</p><p>To create my initial Hello World I've taken the most obvious approach and just cut-and-paste the code off the front page of the Mojolicious website, then stripped out the param-handling stuff, and modified the rest to something obvious looking. I've also added in strict and warnings, which the sample doesn't have.</p><p>Before attempting to run it, I have the following.</p><blockquote><div><p> <tt>#!/usr/bin/perl<br> &nbsp; <br>use strict;<br>use warnings;<br>use Mojolicious::Lite;<br> &nbsp; <br>get '/' =&gt; 'index';<br> &nbsp; <br>shagadelic;<br> &nbsp; <br>__DATA__<br> &nbsp; <br>@@ index.html.ep<br>&lt;html&gt;<br> &nbsp; &lt;body&gt;<br>&nbsp; Hello World!<br> &nbsp; &lt;/body&gt;<br>&lt;/html&gt;</tt></p></div> </blockquote><p>Looking at this code, it seems that everything is template based. This should be a good thing in general, as I'm a heavy Dreamweaver user and don't much like generating pages from raw code.</p><p>So far, it seems fairly simple. My main problem is that I have no idea what the hell "shagadelic" does, although I suspect it's some kind of way of saying "done". Whatever it is for, it annoys me enormously and dates the framework to (I assume) the release date of one of the Austin Powers movies. I get the feeling it is going to make Mojo feel more and more dated over time.</p><p>And they don't use strict or warnings, which seems a bit iffy.</p><p>When I run this helloworld.pl script, I get a handy little block of quite informative help text for my application for free.</p><blockquote><div><p> <tt>C:\cpan\trunk\Top100-Mojo&gt;perl helloworld.pl<br>usage: helloworld.pl COMMAND [OPTIONS]<br> &nbsp; <br>Tip: CGI, FastCGI and PSGI environments can be automatically detected very<br>&nbsp; &nbsp; &nbsp;often and work without commands.<br> &nbsp; <br>These commands are currently available:<br>&nbsp; generate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Generate files and directories from templates.<br>&nbsp; inflate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Inflate embedded files to real files.<br>&nbsp; routes&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Show available routes.<br>&nbsp; cgi&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Start application with CGI backend.<br>&nbsp; daemon&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Start application with HTTP 1.1 backend.<br>&nbsp; daemon_prefork&nbsp; &nbsp;Start application with preforking HTTP 1.1 backend.<br>&nbsp; fastcgi&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Start application with FastCGI backend.<br>&nbsp; get&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Get file from URL.<br>&nbsp; psgi&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Start application with PSGI backend.<br>&nbsp; test&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Run unit tests.<br>&nbsp; version&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Show versions of installed modules.<br> &nbsp; <br>See 'helloworld.pl help COMMAND' for more information on a specific command.</tt></p></div> </blockquote><p>Running the obvious "perl helloworld.pl daemon" like it says on the website and connecting to http://localhost:3000/ I get a simple working "Hello World!" response first time.</p><p>So far so good then, except for the rather dead website. And no need to try any of the support channels yet either.</p><p><b>Dancer - Getting to Hello World</b></p><p>The Dancer website seems quite a bit more enticing than the Mojo website, at least superficially. There's evidence of more attention to some of the visual details, with more design elegance and things like source code syntax highlighting.</p><p>Clicking through the links, however, it's clear information is still a bit thin on the ground. And the "latest release" version on the download page is behind the version on CPAN, but not by much.</p><p>The website generally has more of a "new and undeveloped" feel to it, compared to Mojo's "mild neglect" feel.</p><p>One nice thing about the website, is that they've dropped a Hello World example directly on the front page for me to copy and paste.</p><p>After some small tweaks for my personal take on Perl "correctness" and legibility (the Dancer guys also don't use strict or warnings...) I have the following.</p><blockquote><div><p> <tt>#!/usr/bin/perl<br> &nbsp; <br>use strict;<br>use warnings;<br>use Dancer;<br> &nbsp; <br>get '/' =&gt; sub { return &lt;&lt;'END_PAGE' };<br>&lt;html&gt;<br> &nbsp; &lt;body&gt;<br>&nbsp; Hello World!<br> &nbsp; &lt;/body&gt;<br>&lt;/html&gt;<br>END_PAGE<br> &nbsp; <br>dance;</tt></p></div> </blockquote><p>The Dancer example is smaller and simpler than Mojo example, and doesn't make template use compulsory. Again, I can't stand this use of non-descriptive functions to end these programs. But at least "dance" is cleaner, is an actual verb, and is a bit less tragic than "shagadelic".</p><p>Instead, tragedy strikes for Dancer when I try to install it.</p><p>Because it doesn't install. Or at least, it doesn't install on Windows. Or perhaps it's just my Vista machine.</p><p>A redirect test is failing with this...</p><blockquote><div><p> <tt>t/03_route_handler/11_redirect.t<nobr> <wbr></nobr>............. 1/?<br>#&nbsp; &nbsp;Failed test 'location is set to http://localhost/'<br>#&nbsp; &nbsp;at t/03_route_handler/11_redirect.t line 36.<br>#&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; got: '//localhost/'<br>#&nbsp; &nbsp; &nbsp;expected: 'http://localhost/'<br> &nbsp; <br>#&nbsp; &nbsp;Failed test 'location is set to<nobr> <wbr></nobr>/login?failed=1'<br>#&nbsp; &nbsp;at t/03_route_handler/11_redirect.t line 44.<br>#&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; got: '//localhost/login?failed=1'<br>#&nbsp; &nbsp; &nbsp;expected: 'http://localhost/login?failed=1'<br># Looks like you failed 2 tests of 9.<br>t/03_route_handler/11_redirect.t<nobr> <wbr></nobr>............. Dubious, test returned 2 (wstat&nbsp; &nbsp;512, 0x200)<br>Failed 2/9 subtests</tt></p></div> </blockquote><p>As a non-expert, that looks pretty serious. Maybe I'd force the install if it wasn't something as essential as redirecting that fails. But this is a pretty ordinary feature, and it's not working, and forcing in general scares me.</p><p>The one saving grace is at least it failed quickly. While not keeping dependencies to zero, they've done a fairly decent job of keeping the dependency list down to a minimum.</p><p>But the most damning factor here is a not that it failed once, but when I follow up by taking a look at their CPAN Testers results. These show failure rates all over the place, up and down, with some big regressions.</p><p>This kind of pattern usually suggests that Dancer is seriously lacking in their QA procedures, or have a complete disregard for platforms or Perl versions other than newer Perls on operating systems they personally have. This makes Dancer a risky choice for me to bet on, because it means it could all go wrong down the line unexpectedly.</p><p>So at this point, I'm going to stop with Dancer for this week, having failed to get Hello World working. We'll see if the Dancer guys can address this before next weekend.</p><p><b>Week 1 Results</b></p><p><i> <b>Best Website - Dancer</b> </i></p><p>While this isn't a massive victory, Mojo's many broken links hurt it, while Dancer shows at least some desire to be pretty, which I take as a hint that it might be easier for me in the future to make on my website pretty too.</p><p><i> <b>Best Installation - Mojo</b> </i></p><p>Zero dependencies and a fast installation that Just Worked, contrasts enormously with the failed installation of Dancer, and its unreliability over time (according to CPAN Testers at least).</p><p>If left to my own devices, I would probably already have committed to Mojo at this point, although reluctantly given Dancer's more desirable prettiness.</p><p><i> <b>Best Hello World - Dancer</b> </i></p><p>This one was quite close. Mojo suffered a bit because it forced its templating syntax onto me during Hello World, while Dancer suffered a bit because I had to resort to a Heredoc in the hello world.</p><p>In the end I'm awarding this to Dancer because of the pain in my brain that the function name "shagadelic" causes. I might have been cool for the first day or two, but long term I just know this is going to become an eyesore in my code.</p><p><i> <b>Overall Leader after Week 1 - Mojo</b> </i></p><p>Despite Dancer beating Mojo two to one on the individual factors, when the time came to do what I needed to do, Mojo installed quickly, gave me some help in the right place, and ran my Hello World without error or argument.</p><p>And Dancer did not these things.</p><p>Clearly, there's some QA work for the Dancer guys to do before next week, and the Mojo guys should probably dust some of the cobwebs off their website at the same time.</p><p>Next week, the competition will continue with database and ORM integration.</p><p>Until then, hopefully the respective teams will be blogging their responses and hopefully dealing with any issues raised.</p> Alias 2010-04-03T17:17:59+00:00 journal Pitting Mojo vs Dancer in a competition to build Top100 2.0 http://use.perl.org/~Alias/journal/40270?from=rss <p>With most of my government hackery now finished, I find myself with a free timeslice for the first time in a while.</p><p>I plan to use the time to rewrite my <a href="http://ali.as/top100">CPAN Top 100</a> website from statically generated to being dynamically generated.</p><p>The main reason for this is that I want to start generating priority and ranking lists for individual authors or, say, the entire dependency tree of Padre in the same way I currently do for the entire CPAN. The underlying theme of the Top100 is around prioritising maintenance, but the toolchain seems to drown out the rest of the modules, by virtue of being needed for everything.</p><p>Having written my <a href="http://geo2gov.com.au/">geo2gov.com.au</a> website in Catalyst (to force myself to finally learn it) I'd like to also take a look at some of the new lightweight toolkits.</p><p>This is mainly because the Top100 database (and the <a href="http://search.cpan.org/perldoc?CPANDB">CPANDB</a> database it is based on) is available as an <a href="http://search.cpan.org/perldoc?ORLite">ORLite</a> model. And tying a light weight ORM to a light weight web framework seems like a natural fit.</p><p>The two that seem to stand out as having sufficiently good project managers who understand the need to build communities around their code are <a href="http://search.cpan.org/perldoc?Dancer">Dancer</a> and <a href="http://search.cpan.org/perldoc?Mojolicious">Mojolicious</a>.</p><p>Since neither of the two looks like it particularly outshines the other on face value, my plan is build the new Top100 website simultaneously in both of them.</p><p>At some point during the process (hopefully near the end) I will declare a winner. The code for the loser will be discarded, and the code for the winner will go on to power the final production top100.cpan.org site.</p><p>The main judging criteria will be based on simplicity, legibility, and how amenable they are to collective maintenance.</p><p>To help evaluate the last criteria accurately, and to spice up the competition rules a bit, I'm going to be building both versions of the site in an open commit environment.</p><p>I will be keeping the code for both implementations in my open repository at <a href="http://svn.ali.as/">http://svn.ali.as/</a> and I will be giving commit access to the authors of both Dancer and Mojolicious (and anyone else they nominate).</p><p>I see many "competitions" (especially in benchmarking) where the person running the competition writes all the code as well (badly) and ends up falsely judging certain entries. And I don't want that in this case.</p><p>While I will try to create the initial functionality for each new page or section of the site, both teams are allowed to refactor or improve anything as they see fit so that the code represents what they see as best showcasing their toolkits.</p><p>HOWEVER, teams take certain risks in "improving" my newbie code.</p><p>Any collective maintenance policy requires that experienced developers try to keep their code understandable for newbies. This keeps the pool of talent both wide and deep, while preventing newbies from accidentally breaking code too complex for them to understand.</p><p>So if the team-contributed changes to show off their toolkits in their respective websites makes it harder for me as a newbie to maintain my code, then they will be judged down accordingly.</p><p>In a similar spirit of newbie and small site friendliness, I will be developing the application on Windows without access to a web server, and deploying it onto a remote Linux server running Apache.</p><p>If building the application requires dependencies or external changes add features that don't work in both of these scenarios, they will be penalised.</p><p>As in real life, I won't be laying out precise scoring methods in advance.</p><p>After each chunk of work, I will assess and comment on my experiences, and assign points for that stage of the work (while trying to remain fair about weighting each task appropriately).</p><p>If you have your own web micro-framework you would like to include in the competition as well, you are welcome to petition for inclusion in the comments below.</p><p>However, be warned that to qualify for inclusion you must demonstrate sufficiently robust project management and community involvement. If you have a low bus-sensitivity(1) score, or are not sufficiently mature yet to make me think you are a viable long-term choice for my site (5 years or more) you won't make the grade for entry.</p><p>So let the fight begin!</p><p>Next post, creating the initial application skeletons!</p><p>(1) Bus Sensitivity is the number of people that would need to be hit by a bus for your project to effectively collapse.</p> Alias 2010-03-26T03:32:24+00:00 journal Perl crime application takes 1st prize at apps4nsw hackathon http://use.perl.org/~Alias/journal/40263?from=rss <p>On Saturday <a href="http://www.nerdsfordemocracy.com/">Nerds for Democracy</a> Jeffery and I launched our bid for victory in the app4nsw competition with a new look at crime in Sydney.</p><p><a href="http://ali.as/crimealert">http://ali.as/crimealert</a></p><p>Although it was done in Perl (and reuses much of the Perl geo toolkit we used to take 2nd place in the Mashup Australia competition) Crime Alert is a lot more about access to data than it is about code.</p><p>With our <a href="http://geo2gov.com.au/">geo2gov.com.au</a> search engine, our strategy for the competition was to target a problem that the government is inherently unable to solve (or could only do so with great difficulty) due to constitutionally-imposed separation of powers between Federal, State and Local government.</p><p>For Crime Alert, the problems we are tackling are all about the limitations of statistics, in particular correlation vs causation and the need to maintain anonymity.</p><p>Historically, Australian governments have reported crime based on local government boundaries. This is partly for historical cost and organisation reasons (New South Wales only got a central crime database in 1997) and partly because government has a very strong position on anonymity in reporting.</p><p>For example, the Australian Census collects is significantly larger and collects significantly more sensitive material than the US Census, and the Australian Bureau of Statistics goes to extreme lengths to ensure that this information can't then be used for stalking, predatory marketing, etc.</p><p>Because crime data is only reported based on groups of 50,000+ people, it is depressingly uniform and not particularly interesting. Unless you are part of government or involved in allocation of police resources, crime statistics serve as nothing more than a curiosity. They just aren't that interesting.</p><p>Crime Alert wouldn't exist at all, except for the chance discovery of a series of PDF reports issued by the NSW Bureau of Crime Statistics and Research which contain crime "heat maps" for a subset of the states local government areas (currently, they only cover about a third of local governments).</p><p>The creation of these reports changes the game completely, because it means that the government is now comfortable they can release crime information at a resolution as low at 50 metres without violating anonymity.</p><p>To get the contours we used for our crime map, we had long discussion with their statisticians to demonstrate they we understood the area, that we would use the data responsibly, and to come to an agreement on particular crime types and metrics that would be both useful and relevant to the public.</p><p>With anonymity preserved, the second challenge was to find a way to present the information that is both simple for the consumer and statistically valid.</p><p>The complications here are numerous. The maps we use are from two years ago in 2008, the resolution is reduced to three zones based on one standard deviation either side of the mean, the crime types we use have strong time factors (particularly assaults), the crime scores don't control for population density.</p><p>But the biggest problem is correlation vs causation. Just because there are a lot of assault where (and when) you are, doesn't mean it's YOU that will be assaulted. So using historical crime density as a predictive factor directly is very very bad.</p><p>That doesn't mean it's not relevant at all though. It just means we can't make blanket statements without on-the-ground information.</p><p>So our application limits itself to providing simple low/medium/high factors for both your location and the time of day, both of which are based on the average for the local government you are in.</p><p>This lets us reduce all the complexity of crime down to a single concept, of being in "the wrong place at the wrong time". And we communicate this via two simple "Here" and "Now" boxes, linked so it is clear that both factors are important.</p><p>Taken to the next iteration, we would implement what a user experience designer told us is officially called "Ambient Personalisation".</p><p>In this form, you don't even show the user an interface.</p><p>Instead, software on your phone will run silently in the background (or on a cron) and from time to time it checks your location with the server.</p><p>If you happen to wander into a High crime zone during a High period, your phone beeps or sends you an SMS or rings you or vibrates to let you know you've wandered into the wrong place at the wrong time.</p><p>But once you've hit this location/time combination once, the device (or the server) knows you are now aware of the problems in this area and it won't bother you again. If you happened to move house into a bad area, after the first week the phone has now hit each of the time warnings, and won't bother you about it again.</p><p>But when you visit later go clubbing somewhere new, or park your car to pick up some groceries after visiting a friend somewhere new, your phone will notice that you've parked somewhere notorious, or that there's been a lot of assaults near this club.</p><p>And it's the warnings about these places you have never been that are the key, particularly in a low crime Western city where the crime is often quite concentrated around particular areas, and which start to make the phone an extension of your own ego instead of just a device you use.</p> Alias 2010-03-24T02:49:38+00:00 journal I've been right to be afraid of statistics http://use.perl.org/~Alias/journal/40251?from=rss <p>Under most circumstances, it's my habit to take something I've learned that I find useful and I'm fairly sure I've learned right, find an useful encapsulation boundary, and push that thing I've learned onto CPAN so I don't have to remember the details of how to do it right later.</p><p>But doing this with statistics has largely eluded me, except for the some of the most primitive mechanisms to joining data producers to statistics consumers.</p><p>Statistics are deeply confusing, and even thought I know they are confusing I still find it hard to make them fit in my head (because implications are often not even predictably confusing to me).</p><p>Fortunately, I can console myself that I'm not the only person for which this is the case, but at least I'm avoiding the use of them correctly.</p><p><a href="http://www.sciencenews.org/view/feature/id/57091/title/Odds_Are,_Its_Wrong">http://www.sciencenews.org/view/feature/id/57091/title/Odds_Are,_Its_Wrong</a></p> Alias 2010-03-18T05:26:08+00:00 journal