tag:blogger.com,1999:blog-139643322008-02-17T22:49:33.182-08:00Two AlphaMatisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comBlogger76125tag:blogger.com,1999:blog-13964332.post-78309752143918963362008-02-17T22:49:00.001-08:002008-02-17T22:49:33.210-08:00Releasing software under an Open Source License to Increase Business ValueReleasing software under an Open Source License can increase the business value of that software.<br /><br /><strong>Why License as Open Source?</strong><br />As a developer when I create software and license it to a customer there are a number of reasons why I might want that license to be an Open Source license. That is, that are a number of ways in which Open Source licenses increase the value of the software to me, the original author. This value points should be weighed against the value created by Closed Source licenses.<br /><strong><br />Open Source Need Not Equal "Free of Charge"</strong><br />Software can be Open Source and fee-for-use and it can be closed-source but free-of-charge.<br /><br />Examples:<br /><br /><ul><li>Embedding the MySQL database in your product: It is Open Source, but you must pay for the right to embed MySQL in your product.</li><li>Microsofts' Internet Explorer web browser is free-of-charge but is Closed Source.</li></ul>Releasing software under an Open Source license does not automatically mean you are allowing all use to be free of charge. Indeed, crafting good Open Source fee-for-use licenses is an area of law which would benefit from more creative efforts.<br /><br /><strong>Value From Increased Networking Utility</strong><br />Many of the value propositions listed below derive from the idea of increasing the human networking utility of my software - that is, as under an Open Source license my software can be used to help create and maintain my connections to other people: developers, potential clients, collaborators, pundits, marketers, etc. and a great deal (maybe most?) of the business value available ("Total Value Available") is obtained through connections and relationships, so anything that promotes good connections to other people has potential business value which should be considered.<br /><br />Closed Source software licenses act in some ways as barriers to creating and maintaining connections to people. Healthy relationships require boundaries, so this is not a question of all-or-nothing but rather one of degree and kind. A lot of what a Closed Source license does is to try and prevent a loss of value, as opposed to providing utility that can lead to an  increase in value.<br /><br />The value that a Closed Source license seeks to create or preserve is based on scarcity and secrecy. The Closed Source License seeks to create a barrier to understanding how the software works, and making it harder for others to reuse or modify the software.  The Closed Source License is addressing the creators' fears that if someone can read the source code they will have an easier time creating a competing product, that it will be easy to copy portions of the code and reuse it without payment and that t will be hard to detect such violations. These are real issues and should be considered before releasing source code in any form.<br /><br /><strong>Specific Kinds of Value Created or Increased by an Open Source License</strong><br />Using an Open Source License for software I create increases its value to me by:<br /><ul><li>Ensuring that I have the right to re-use the software for another project/client.</li><li>Increasing the likelihood that my software will be widely used, and thus I will be known to a wider market, and possibly gain market-share and "mind-share."</li><li>Increasing the likelihood that my software will be improved. I gain by being associated with the higher-quality experiences the users have, even though some improvements are made by others, as the original author, some of the goodness rubs off on me.</li><li>Making it easier to use my software as a marketing tool - I can show the code to prospective clients and collaborators and partners. Increasing the human-networking utility of my software is a</li><li>Making it easier to incorporate other Open Source Software into my product, thus giving me a much wider range of options for adding features and making improvements, so I can respond to change requests and new opportunities much faster than if any change had to be implemented <em>de novo</em>.</li><li>Providing an effective avenue for the widest possible expert review of the softwares' security. For example, Open Source software that handles vote counting  will likely inspire higher confidence and thus have a greater value.</li></ul><strong>Some Ideas For Open Source Licenses<br /></strong>What can/should one put in a License that is part of a Software Development Contract? I am thinking here of things that specifically relate to adding value for the licensor, for example:<br /><br /><ul><li>Non-exclusivity. Licensor can use the software for other projects.</li><li>Licensor has the right to list the Licensee in marketing materials (e.g. a web site) as a Licensee of the Software.</li><li>Prescribing a mechanism for Licensee to "post-back" changes to the software.</li></ul>There are probably a lot more things to consider along these lines - how releasing software as Open Source can increase the softwares' value to the releasor.<br /><strong><br />SEE ALSO</strong><br /><br />Some widely used Open Source Licenses:<br /><ul><li>apache  <a href="http://apache.org/licenses/LICENSE-2.0">http://apache.org/licenses/LICENSE-2.0</a></li><li>artistic        <a href="http://opensource.org/licenses/artistic-license.php">http://opensource.org/licenses/artistic-license.php</a></li><li>bsd    <a href="http://www.opensource.org/licenses/bsd-license.php">http://www.opensource.org/licenses/bsd-license.php</a></li><li>gpl    <a href="http://www.opensource.org/licenses/gpl-license.php">http://www.opensource.org/licenses/gpl-license.php</a></li><li>lgpl    <a href="http://www.opensource.org/licenses/lgpl-license.php">http://www.opensource.org/licenses/lgpl-license.php</a></li><li>mit    <a href="http://opensource.org/licenses/mit-license.php">http://opensource.org/licenses/mit-license.php</a></li><li>mozilla <a href="http://opensource.org/licenses/mozilla1.1.php">http://opensource.org/licenses/mozilla1.1.php</a></li><li>perl    <a href="http://dev.perl.org/licenses/">http://dev.perl.org/licenses/</a></li></ul><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/marketing" rel="tag">marketing</a>, <a href="http://www.technorati.com/tag/open source" rel="tag">open source</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-45086747034862480352008-02-07T06:50:00.001-08:002008-02-07T06:52:42.897-08:00Markets are not mathematical creatures.Stock markets look like mathematical phenomena, but they are not. Stock markets are psychological phenomena.<br /><br />See "<a href="http://www.amazon.com/Demon-Our-Own-Design-Innovation/dp/0471227277" title="amazon link">Demon of our own Design</a>."Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-30091427750483889142007-12-29T01:27:00.001-08:002008-01-17T08:16:27.053-08:00BuildBot: Continuous Integration SystemI've spent some of this holiday season learning how to set up BuildBot (<a href="http://buildbot.net/" title="BuildBot main web site">http://buildbot.net/</a>) which is a <a href="http://en.wikipedia.org/wiki/Continuous_Integration" title="Continuous Integration page at Wikipedia">Continuous Integration</a> system that is especially aimed at open-source style projects: You set up a central "build master", and one or more "build slaves" - and it is very easy for someone to set up a new build slave, so if you have some new platform you want to test a project on you can add a build slave. The build-master admin has to add your slave on the master side, and the slave needs to be able to access the source code repository (CVS in my case.)<br /><br />I've got three of my Perl projects from my CVS repo running under BuildBot now, and it's all working, except email notification of build status - no email is getting to the mail server, and i have yet to learn how to debug that.<br /><br />When I commit a change to my CVS repository for one of these projects that kicks off a build on one or more build slaves, which checks out the latest code, and runs all the unit tests. The build master shows the results in a web page.<br /><br />I've got about 9.5 hours into it, (out of an initial estimate of 12) include various yak-shaving activities.<br /><br />For now I have the build status pages for the three projects at:<br /><ul><li><a href="http://buildbot.eigenstate.net:8010/" title="Perl::Metrics::Simple buildbot page">Perl-Metrics-Simple</a> - Building using both MakeMaker and Module::Build. This distro provides modules for a utility program to count lines, packages, subs and complexity of Perl files.</li><li><a href="http://buildbot.eigenstate.net:8020/" title="DBIx::Wrapper::VerySimple buildbot page">DBIx-Wrapper-VerySimple</a> - Simplify use of DBI.</li><li><a href="http://buildbot.eigenstate.net:8030/" title="Text::TagTemplate buildbot page">Text-TagTemplate</a> - Lightweight flexible template parsing module.</li></ul>See also my <a href="http://twoalpha.blogspot.com/2007/12/continuous-integration-improving.html">earlier posting with a review of a book on Continuous Integration</a> and a link to a comparison of several CI systems.<br /><br />2007-12-29 update: Starting to add notes to the <a href="http://perl-qa.hexten.net/wiki/index.php/Buildbot" title="BuildBot page on the Perl QA Wiki">Perl-QA Wiki.</a><br />2008-01-06 update: The email issue was caused by a typo in my master.cfg file.<br /><code>subject='%(builder) BUILD STATUS',</code> WRONG<br /><code>subject='%(builder)s BUILD STATUS',</code> CORRECT<br />Note the missing 's' after the closing parenthesis - it is part of a  Python extended printf statement.<br />Also, I have now added a fourth buildmaster which builds the Parrot project. All my buildbot configurations are now at: <a href="http://www.eigenstate.net/buildbot/masters.html">http://www.eigenstate.net/buildbot/masters.html</a><br />2008-01-17 update: The open source <a href="http://webkit.org/" title="webkit project home page">webkit</a> project uses buildbot - you can see their build status at <a href="http://build.webkit.org/" title="link to webkit build page">http://build.webkit.org/</a><br /><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/continuous integration" rel="tag">continuous integration</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a>, <a href="http://www.technorati.com/tag/software testing" rel="tag">software testing</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-41947255764680789822007-12-01T16:32:00.001-08:002007-12-30T17:58:14.125-08:00Continuous Integration - Improving Software Quality and Reducing RiskPaul Duvall, Steve Matyas, and Andrew Glover have written a fine book describing the value and practice of <a href="http://en.wikipedia.org/wiki/Continuous_Integration">Continuous Integration</a> or CI for short. If you have heard of CI and want to learn more about it, or if you want to help educate others about it, this book is a very good place to start.<br /><br />Continuous Integration is a software development practice intended to notify the development team as soon as possible when a defect is introduced. Typically when CI is being used there is an automated system which the builds the entire project many times each day from its source code to its complete form, and all its automated tests and other automated quality assurance tools can be brought to bear.<br /><br />The authors of "Continuous Integration" repeatedly emphasize the role that CI has in reducing risk in software development and constantly provide examples of specific practices that support and benefit from CI, for example frequent commits to a version control system, automated tests,  automated code analysis (test coverage, code complexity, duplication, etc.)<br /><br />I think this book would be great for a leader that is trying to convince their team or their management of the value of CI, as well as for a team implementing CI for the first time as an aid to deciding what system to choose and what aspects to implement first.<br /><br /><a href="http://www.bookpool.com/sm/0321336380" target="_blank" title="link to Bookpool.com">Continuous Integration: Improving Software Quality and Reducing Risk</a><br />by Paul Duvall, Steve Matyas, Andrew Glover<br />Paperback: 336 pages<br />Publisher: Addison-Wesley Professional (July 9, 2007)<br />Language: English<br />ISBN-10: 0321336380<br />ISBN-13: 978-0321336385<br /><br />See also:<br /><ul><li>Codehause.org has a <a href="http://docs.codehaus.org/display/DAMAGECONTROL/Continuous+Integration+Server+Feature+Matrix" target="_blank" title="link to codehause.org CI comparison matrix">side-by comparison of many Continuous Integration systems</a>.</li><li><a href="http://perl-qa.hexten.net/wiki/index.php/Continuous_Integration">Perl QA Continuous Integration wiki page</a>.</ul><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/agile" rel="tag">agile</a>, <a href="http://www.technorati.com/tag/continuous integration" rel="tag">continuous integration</a>, <a href="http://www.technorati.com/tag/extreme programming" rel="tag">extreme programming</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a>, <a href="http://www.technorati.com/tag/software testing" rel="tag">software testing</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-62283162820357504862007-11-19T19:26:00.001-08:002007-11-19T19:28:01.164-08:00Time Machine Very Slow on LeopardTime Machine will run very slowly if an anti-virus utility such as Norton is scanning each file as it is written or changed on the backup disk.<br /><br />The fix for this is to go into the Norton Auto-Protect Preference Pane of System Preferences and add your backup disk in the SafeZones tab.<br /><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/Mac OS X" rel="tag">Mac OS X</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-86608588005129134992007-09-08T22:44:00.000-07:002007-09-15T15:32:07.824-07:00cyradm fails: Can't locate auto/Cyrus/IMAP/imclient_ha.al in @INCAttempting to login via cyradm fails because of a missing library.<br /><br /><br /><span style="color:#ff0000;">UPDATE 2007-09-15: I believe I have a fix for this. In Cyrus/IMAP/Shell.pm change line 780 from:<br /><br /></span><p style="text-indent:20pt;"><span style="font-family:monospace;color:#ff0000;font-size:9pt;">if (Cyrus::IMAP::imclient_havetls()) {</span><span style="color:#ff0000;"><br /></span></p>to</p><p style="text-indent:20pt;"><span style="font-family:monospace;color:#ff0000;font-size:9pt;">if (Cyrus::IMAP::havetls()) {</span><span style="color:#ff0000;"><br /></span></p><br />See also: <a href="https://bugzilla.andrew.cmu.edu/show_bug.cgi?id=2988" title="bug report">https://bugzilla.andrew.cmu.edu/show_bug.cgi?id=2988</a><br /><span style="font-family:monospace;font-size:9pt;"><br /></span>Name : cyrus-imapd<br />Arch : x86_64<br />Version: 2.3.9<br />Release: 6.fc6<span style="font-family:monospace;font-size:9pt;"><br /><br />$ uname -a<br />Linux galadriel 2.6.22.1-32.fc6 #1 SMP Wed Aug 1 14:30:16 EDT 2007 x86_64<br />x86_64 x86_64 GNU/Linux</span><br /><span style="font-family:monospace;font-size:9pt;">$ cyradm</span><br /><span style="font-family:monospace;font-size:9pt;">cyradm&gt; login matisse<br />Can't locate auto/Cyrus/IMAP/imclient_ha.al in @INC (@INC contains:<br />/usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi<br />/usr/lib64/perl5/site_perl/5.8.7/x86_64-linux-thread-multi<br />/usr/lib64/perl5/site_perl/5.8.6/x86_64-linux-thread-multi<br />/usr/lib64/perl5/site_perl/5.8.5/x86_64-linux-thread-multi<br />/usr/lib/perl5/site_perl/5.8.8 /usr/lib/perl5/site_perl/5.8.7<br />/usr/lib/perl5/site_perl/5.8.6 /usr/lib/perl5/site_perl/5.8.5<br />/usr/lib/perl5/site_perl<br />/usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux-thread-multi<br />/usr/lib64/perl5/vendor_perl/5.8.7/x86_64-linux-thread-multi<br />/usr/lib64/perl5/vendor_perl/5.8.6/x86_64-linux-thread-multi<br />/usr/lib64/perl5/vendor_perl/5.8.5/x86_64-linux-thread-multi<br />/usr/lib/perl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl/5.8.7<br />/usr/lib/perl5/vendor_perl/5.8.6 /usr/lib/perl5/vendor_perl/5.8.5<br />/usr/lib/perl5/vendor_perl /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi<br />/usr/lib/perl5/5.8.8 .) at<br />/usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux-thread-multi/Cyrus/IMAP/Shell.pm<br />line 780</span><br /><span style="font-family:monospace;font-size:9pt;">cyradm&gt;</span><br /><br />Evidently I am not the only one getting this problem. See: <a href="http://use.perl.org/~jk2addict/journal/32136" title="another users report">http://use.perl.org/~jk2addict/journal/32136</a><br />Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-11494117934244562112007-05-17T23:16:00.001-07:002007-05-17T23:16:45.494-07:00Social Dynamics of Pair Programming<a href="http://www.stanford.edu/~jchong/research/chong-icse2007.pdf">The Social Dynamics of Pair Programming</a><br /><br />Interesting paper by Jan Chong and Tom Hurlbutt at Stanford University.<br /><br />Here's the Abstract:<br /><blockquote>This paper presents data from a four month ethno-<br />graphic study of professional pair programmers from<br />two software development teams. Contrary to the cur-<br />rent conception of pair programmers, the pairs in this<br />study did not hew to the separate roles of “driver” and<br />“navigator”. Instead, the observed programmers<br />moved together through different phases of the task,<br />considering and discussing issues at the same strategic<br />“range” or level of abstraction and in largely the same<br />role. This form of interaction was reinforced by fre-<br />quent switches in keyboard control during pairing and<br />the use of dual keyboards. The distribution of expertise<br />among the members of a pair had a strong influence on<br />the tenor of pair programming interaction. Keyboard<br />control had a consistent secondary effect on decision-<br />making within the pair. These findings have implica-<br />tions for software development managers and practi-<br />tioners as well as for the design of software develop-<br />ment tools.</blockquote>(<a href="http://www.stanford.edu/~jchong/research/chong-icse2007.pdf" title="PDF Document">Link to PDF version</a> or <a href="http://72.14.253.104/search?q=cache:kJVEtrZg4HsJ:www.stanford.edu/~jchong/research/chong-icse2007.pdf+chong-icse2007&amp;hl=en&amp;ct=clnk&amp;cd=1&amp;gl=us&amp;client=firefox-a">Google HTML view</a><span style="color:#1919ff;text-decoration:underline;">)<br /></span><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/agile" rel="tag">agile</a>, <a href="http://www.technorati.com/tag/extreme programming" rel="tag">extreme programming</a>, <a href="http://www.technorati.com/tag/pair programming" rel="tag">pair programming</a>, <a href="http://www.technorati.com/tag/XP" rel="tag">XP</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-33311490562701197852007-05-06T11:23:00.001-07:002007-05-06T11:23:22.740-07:00Finding which jar file provides a Java class.Given a class name such as:<br /><br /><code>org.springframework.mail.javamail.MimeMessageHelper</code><br /><br /><a href="http://www.jarfinder.com/" title="Find java classes in jar files">www.jarfinder.com</a> provides a fast easy way to find out which .jar file(s) provide the class, with links to the organization and download site for each one.<br /><br />For example:<br /><br /> <a href="http://www.jarfinder.com/?class=org.springframework.mail.javamail.SmartMimeMessage&amp;submit=search" title="Example of search-by-class">http://www.jarfinder.com/?class=org.springframework.mail.javamail.SmartMimeMessage&#38;submit=search</a><br /><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/java" rel="tag">java</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-22706499983897188982007-04-20T08:54:00.000-07:002007-04-26T08:01:42.912-07:00Estimating Value of a Possible Software Project<span style="font-family:Arial;"><strong>What factors to consider when estimating the value of a possible software project?<br /></strong></span><span style="font-family:Arial;"><br />I made a list various factors I have considered, more or less formally as the case may be, when estimating the value of undertaking a development project.<br />When I thought about how I measure these factors I found that I generally think of them as each having a probability-distribution.<br />Instead of "This feature will cut response time in half", something like "This has a 90% chance of getting of cutting response time by 10%, and maybe a 30% chance of cutting it by 60%."<br />What factors do you find are most worth spending time to consider?<br />How might you express those factors in making a go/no-go decision on a project?<br /><br />Examples, in no particular order:<br /></span><span style="font-family:Arial;"><br /></span><span style="font-family:Arial;"><strong>Value Factors: What will we get from this software?</strong></span><span style="font-family:Arial;"><br /><br /></span><ul><li><span style="font-family:Arial;"> capabilities - but then I ask, what is the value of each capability?</span></li><li><span style="font-family:Arial;">Wh</span><span style="font-family:Arial;">at is the "total market available" for this software/feature?</span></li><li><span style="font-family:Arial;">How much of that market can we expect to get?</span></li><li><span style="font-family:Arial;">What new markets will this get us into?</span></li><li><span style="font-family:Arial;">What cost(s) will this feature help us avoid or reduce?</span></li><li><span style="font-family:Arial;">What value does this bring to our team - new skills, experience, etc.</span></li><li><span style="font-family:Arial;">How much fund will this be?</span></li><li><span style="font-family:Arial;">Synergy with other projects?</span></li><li><span style="font-family:Arial;">What is the time-to-market value? (what is the value of releasing early vs. later?) Taken to the extreme, that question turns into a cost question: "What is the cost of not releasing at all?"</span></li><li><span style="font-family:Arial;">Reputation value: What value does this bring to our brand?</span></li></ul><span style="font-family:Arial;"><strong>Cost Factors: What will it cost us?</strong></span><span style="font-family:Arial;"><br /></span><ul><li><span style="font-family:Arial;">Labor costs</span></li><li><span style="font-family:Arial;">Hardware costs</span></li><li><span style="font-family:Arial;">Licensing costs</span></li><li><span style="font-family:Arial;">Costs associated with various risk factors:</span></li><li><span style="font-family:Arial;">Reputation cost for overreaching.</span></li><li><span style="font-family:Arial;">Human cost (burn-out, staff turnover) of doing too much.</span></li><li><span style="font-family:Arial;">New or increased legal or financial liabilities.</span></li><li><span style="font-family:Arial;">Delay to other projects.</span></li></ul><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/estimating" rel="tag">estimating</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-45745158612135305222007-01-21T22:17:00.000-08:002007-01-21T22:28:55.253-08:00JUnit-Style XML from Perl Test FilesHere is an experimental program that runs Perl test files and produces the same sort of XML output as the<a href="http://ant.apache.org/manual/OptionalTasks/junit.html"> &lt;junit&gt; ant task</a>.<br />Getting this XML output is helpful when running Perl tests under <a href="http://cruisecontrol.sourceforge.net/">CruiseControl</a>.<br /><br /><pre>#!/usr/bin/perl<br /><br />use strict;<br />use warnings;<br /><br />use Test::Harness::Straps;<br />use Time::HiRes qw(gettimeofday tv_interval);<br />use XML::Generator ':noimport';<br /><br />my @files = @ARGV;<br /><br />my $strap = Test::Harness::Straps-&gt;new;<br />my $generator = XML::Generator-&gt;new(':pretty');<br /><br />my @properties = _get_properties($generator);<br />my $test_results = _run_tests( $strap, $generator, @files );<br /><br />my $xml = _get_junit_xml( $generator, \@properties, $test_results );<br /><br />print "$xml\n";<br /><br />exit;<br /><br />#-------------------------------------------------------------------------------<br /><br />sub _get_junit_xml {<br /> my ( $generator, $properties, $test_results ) = @_;<br /><br /> my $system_out = 'system-out';<br /> my $system_err = 'system-err';<br /> my $xml = '';<br /> $xml .= "\n";<br /> $xml .= $generator-&gt;testsuite(<br /> {<br /> errors =&gt; 0,<br /> failures =&gt; $test_results-&gt;{total_failures},<br /> name =&gt; 'name of the test suite',<br /> tests =&gt; $test_results-&gt;{total_tests},<br /> 'time' =&gt; $test_results-&gt;{total_time},<br /> },<br /> $generator-&gt;properties(@properties),<br /> @{ $test_results-&gt;{test_cases} },<br /> $generator-&gt;$system_out(),<br /> $generator-&gt;$system_err(),<br /><br /> );<br /> return $xml;<br />}<br /><br />sub _run_tests {<br /> my ( $strap, $generator, @files ) = @_;<br /> my @test_cases = ();<br /> my $total_tests = 0;<br /> my $total_time = 0;<br /> my $total_failures = 0;<br /><br /> foreach my $test_file (@files) {<br /> my $start_time = [gettimeofday];<br /> my $file_results = $strap-&gt;analyze_file($test_file);<br /> my $elapsed_time = tv_interval( $start_time, [gettimeofday] );<br /> $total_time += $elapsed_time;<br /> foreach my $assertion ( @{ $file_results-&gt;details } ) {<br /> if ( _skip($assertion) ) {<br /> next;<br /> }<br /> $total_tests++;<br /> $total_failures += _is_failure($assertion);<br /> my $test_case = {<br /> classname =&gt; $test_file,<br /> name =&gt; $assertion-&gt;{name},<br /> 'time' =&gt; 0,<br /> };<br /> push @test_cases, $generator-&gt;testcase($test_case);<br /> }<br /> }<br /> my $test_results = {<br /> total_time =&gt; $total_time,<br /> test_cases =&gt; \@test_cases,<br /> total_tests =&gt; $total_tests,<br /> total_failures =&gt; $total_failures,<br /> };<br /> return $test_results;<br />}<br /><br />sub _skip {<br /> my $assertion = shift;<br /> return $assertion-&gt;{type} =~ / skip | todo /x;<br />}<br /><br />sub _is_failure {<br /> my $assertion = shift;<br /> return !$assertion-&gt;{ok};<br />}<br /><br />sub _get_properties {<br /> my $generator = shift;<br /> my @properties = ();<br /> foreach my $key ( sort keys %ENV ) {<br /> push @properties,<br /> $generator-&gt;property( { name =&gt; "$key", value =&gt; $ENV{$key} } );<br /> }<br /> return @properties;<br />}<br /><br />__END__<br /><br />=head1 NAME<br /><br />junit_xml.pl - Run Perl tests and get JUnit-style XML output<br /><br />=head1 SYNOPSIS<br /><br /> junit_xml.pl file1 [ file2 ... ]<br /><br />=head1 DESCRIPTION<br /><br />Experimental script to run perl test files and produce the<br />same XML output as produced by the &lt;junit&gt; ant task.<br /><br />=head1 DEPENDENCIES<br /><br /> Test::Harness<br /> Time::HiRes<br /> XML::Generator <br /><br />=head1 BUGS<br /><br /> - Doesn't do anything with the STDERR from tests.<br /> - Doesn't fill in the 'errors' attribute in the &lt;testsuite&gt; element.<br /> - Doesn't handle when all tests in file are skipped (skip_all)<br /> - Doesn't get the elapsed time for each 'test' (i.e. assertion.)<br /><br /><br />=head1 AUTHOR<br /><br />Matisse Enzer &lt;matisse@matisse.net&gt;<br /><br />=head1 COPYRIGHT &#38; LICENSE<br /><br />Copyright (c) 2007 Matisse Enzer. All Rights Reserved.<br /><br />This program is free software; you can redistribute it and/or modify it<br />under the same terms as Perl itself.<br />=cut<br /></pre><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/Perl" rel="tag">Perl</a>, <a href="http://www.technorati.com/tag/software testing" rel="tag">software testing</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-46515474942419514482007-01-21T12:01:00.001-08:002007-01-21T14:25:41.607-08:00Unix shell: Finding the run-time directory of a scriptI've been trying to come up with an elegant way, in a shell script, to find the full path of the directory in which the script is located.<br /><br />So far, I have this, which works for bash but not for sh (sh does not support substring expansion on variables):<br /><br /><br /><pre> #!/usr/local/bin/bash -x<br /> # Finds the full path to the directory containing this script<br /> <br /> dir_containing_this_script=""<br /> script_dirname=`dirname $0`<br /> first_char="${script_dirname:0:1}" ; # Starting at index 0, 1 character<br /> case "$first_char" in<br /> ("/")<br /> # It's a full path. Use it unmodified.<br /> dir_containing_this_script="${script_dirname}"<br /> ;;<br /> (*)<br /> # Strip leading . characters<br /> while [ "${first_char}" = "." ]; do<br /> script_dirname="${script_dirname:1}" ; # substring from index 1 to end<br /> first_char="${script_dirname:0:1}"<br /> done<br /> current_dir=`pwd`<br /> if [ -s "${script_dirname}" ] ; then<br /> dir_containing_this_script="${current_dir}/${script_dirname}"<br /> else <br /> dir_containing_this_script="${current_dir}"<br /> fi<br /> ;;<br /> esac<br /> <br /> echo "$dir_containing_this_script"<br /></pre><br /><br />Update: Eric M on The WELL posted this most excellent solution:<br /><pre><br /> dn=`dirname $0`<br /> path=`(cd $dn; pwd)`<br /> echo "path = $path"<br /></pre><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/programming" rel="tag">programming</a>, <a href="http://www.technorati.com/tag/unix" rel="tag">unix</a>, <a href="http://www.technorati.com/tag/unix shell" rel="tag">unix shell</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-81260584775297715202007-01-19T00:05:00.001-08:002007-01-19T00:13:24.617-08:00Super Easy Graphics Programming<a href="http://www.allartburns.org/" title="All Art Burns">Eric Townsend</a> pointed me to <a href="http://processing.org/" title="Processing Home Page">Processing</a> - super easy programming environment for creating graphics programs.<br /><br />Here's <a href="http://eigenstate.net/processing_example/" title="Applet Crated with Processing">an applet I generated from it in a few minutes work,</a> starting with an example Eric posted on <a href="http://well.com/" title="Applet Crated with Processing">The WELL</a>.<br /><br /><pre>/// start<br />void setup() {<br /> size(600,600);<br />}<br /><br />void draw(){<br /> background(255);<br /><br /> int left_x = 0;<br /> int right_x = width;<br /> int top_y = 0;<br /> int bottom_y = height;<br /> int light_green = #99FF99;<br /> int light_blue = #66CCFF;<br /> int light_yellow = #FFCC66;<br /> int pale_red = #FF3366;<br /><br /> for (int n=0; n &lt; 100; n++) {<br /> int y_of_n = n * (bottom_y/100);<br /> int x_of_n = n * (right_x/100);<br /><br /> stroke(pale_red);<br /> line(left_x,y_of_n,mouseX,mouseY);<br /><br /> stroke(light_yellow);<br /> line(right_x,y_of_n,mouseX,mouseY);<br /><br /> stroke(light_blue);<br /> line(x_of_n,0,mouseX,mouseY);<br /><br /> stroke(light_green);<br /> line(x_of_n,bottom_y,mouseX,mouseY);<br /> }<br />}<br /><br />/// end<br /></pre><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/graphics" rel="tag">graphics</a>, <a href="http://www.technorati.com/tag/programming" rel="tag">programming</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-79511149129760582592006-12-26T21:04:00.000-08:002006-12-26T21:07:54.050-08:00Provider Injection, not Dependency InjectionThe term "provider injection" should replace the term "dependency injection."<br /><br />The term misleads by seeming to say that you are "injecting" a dependency. This would mean that the thing got the "dependency" injected into it now depends upon something that it didn't depend upon before. This is not what "dependency injection" means.<br /><br />The term "dependency injection" actually means that if Object A depends upon having a "B" object that you "inject" a B object into object A (instead of object A fetching or creating a B on its own.) A classic example would be a Person object that depends upon having a database connection in order to create/update/edit/delete people in the database. Instead of the Person object creating its own database connection it gets one passed to it (i.e. "injected") perhaps as an argument to its constructor. But, see, you are not injecting a <strong>dependency</strong>. You are injecting a <strong>provider</strong>.<br /><br />A "dependency" is not the thing upon which you depend. The thing you depend upon is a tool, resource, skill, or capability and you get those things by making them yourself, or from a <strong>provider</strong>.<br /><br />So, I think the term "<strong>provider injection</strong>" should replace the term "dependency injection."<br /><br />By the way, I want to thank <a href="http://m2ward.blogspot.com/i" title="Mike's blog">Mike Ward</a> for originally introducing me to the term "dependency injection" - whatever phrase is used, the actual practice is one I have done in the past and it is good to have a phrase to describe this technique.<br /><br />See also:<br /><a href="http://en.wikipedia.org/wiki/Dependency_injection" title="wikipedia entry">Wikipedia entry on Dependency Injection</a> (which I have attempted to edit.)<br /><a href="http://www.martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a> - 2004 article by <a href="http://martinfowler.com/">Martin Fowler</a><br /><a href="http://www.springframework.org/node/54">Spring in Action</a> - Book on Spring<br /><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/inversion of control" rel="tag">inversion of control</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-32191478434324246642006-12-09T15:22:00.000-08:002006-12-13T21:29:39.058-08:00countperl - count lines, packages, subs and complexity of Perl filesI recently released a new version of <strong><a href="http://search.cpan.org/dist/Perl-Metrics-Simple">Perl::Metrics::Simple</a></strong> (0.03) that includes the <code style="font-style: italic;">countperl</code> script. The program reports on how complicated your Perl code is - giving you direction on where to start <a href="http://en.wikipedia.org/wiki/Refactoring">refactoring</a> it to make it easier to understand, debug, and maintain. Try to keep the McCabe Complexity at 9 or less for every subroutine and "main" section of your code.<br /><em>countperl</em> is a command line tool that you execute with a list of one or more files andor directories. The program examines the named files and recursivesly searches named directories for Perl files.<br />The <em>countperl</em> program produces a report on <em>STDOUT</em> of total lines, packages, subroutines/methods, the minimum, maximum, mean, standard deviation, and median size and mccabe_complexity (aka <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a>) of subroutines and the 'main' portion of each file (everything not in a subroutine.)<br /><br /><strong>Output Format</strong><br /><br />Line counts do not include comments nor pod.<br />The current output format is human-readable text. For example, a report based on analyzing three files might look like this:<br /><pre><span style="color:#666600;"> Perl files found: 3</span><br /><br /><span style="color:#666600;"> Counts</span><br /><span style="color:#666600;"> ------</span><br /><span style="color:#666600;"> total code lines: 856</span><br /><span style="color:#666600;"> lines of non-sub code: 450</span><br /><span style="color:#666600;"> packages found: 3</span><br /><span style="color:#666600;"> subs/methods: 42</span><br /><br /><span style="color:#666600;"> Subroutine/Method Size</span><br /><span style="color:#666600;"> ----------------------</span><br /><span style="color:#666600;"> min: 3 lines</span><br /><span style="color:#666600;"> max: 32 lines</span><br /><span style="color:#666600;"> mean: 9.67 lines</span><br /><span style="color:#666600;"> std. deviation: 7.03</span><br /><span style="color:#666600;"> median: 7.50</span><br /><br /><span style="color:#666600;"> McCabe Complexity</span><br /><span style="color:#666600;"> -----------------</span><br /><span style="color:#666600;"> Code not in any subroutine::</span><br /><span style="color:#666600;"> min: 1</span><br /><span style="color:#666600;"> max 1</span><br /><span style="color:#666600;"> mean: 1.00</span><br /><span style="color:#666600;"> std. deviation: 0.00</span><br /><span style="color:#666600;"> median: 1.00</span><br /><br /><span style="color:#666600;"> Subroutines/Methods:</span><br /><span style="color:#666600;"> min: 1</span><br /><span style="color:#666600;"> max: 5</span><br /><span style="color:#666600;"> avg: 1.00</span><br /><span style="color:#666600;"> std. deviation: 1.36</span><br /><span style="color:#666600;"> median: 1.00</span><br /><br /><span style="color:#666600;"> Tab-delimited list of subroutines, with most complex at top</span><br /><span style="color:#666600;"> -----------------------------------------------------------</span><br /><span style="color:#666600;"> complexity sub path size</span><br /><span style="color:#666600;"> 5 is_perl_file lib/Perl/Metrics/Simple.pm 11</span><br /><span style="color:#666600;"> 5 _has_perl_shebang lib/Perl/Metrics/Simple.pm 13</span><br /><span style="color:#666600;"> 5 _init lib/Perl/Metrics/Simple/Analysis/File.pm 30</span><br /><span style="color:#666600;"> 4 find_files lib/Perl/Metrics/Simple.pm 11</span><br /><span style="color:#666600;"> 4 new lib/Perl/Metrics/Simple/Analysis.pm 10</span><br /><span style="color:#666600;"> 4 is_ref lib/Perl/Metrics/Simple/Analysis.pm 8</span><br /></pre><br /><p>Chris Chedgey has a posting that describes a common situation - you have <a href="http://chris.headwaysoftware.com/2006/10/reducing_comple.html" title="Complexity Debt - don't fix it - keep a lid on it">accumulated a huge pile of "complexity debt"</a> - well, using <strong>countperl</strong> is one tool to help "keep a lid on it."</p><br /><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/Perl" rel="tag">Perl</a>, <a href="http://www.technorati.com/tag/programming" rel="tag">programming</a>, <a href="http://www.technorati.com/tag/refactoring" rel="tag">refactoring</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a>, <a href="http://www.technorati.com/tag/software testing" rel="tag">software testing</a>, <a href="http://www.technorati.com/tag/static analysis" rel="tag">static analysis</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-3784187058276376942006-11-02T05:51:00.000-08:002006-11-02T06:19:32.145-08:00Very Simple Wrapper for Perl DBII've released a new Perl module: <b><code>DBIx::Wrapper::VerySimple</code></b> which provides a very simple (object-oriented) wrapper around DBI.<br /><br /><code></code><a href="http://search.cpan.org/dist/DBIx-Wrapper-VerySimple/"></a><code>DBIx::Wrapper::VerySimple</code> provides three methods<code style="font-style: italic;"></code> <code style="font-style: italic;"></code> that between them cover about 98% of the SQL calls I've seen in Perl code over the years:<br /><ul><li><code style="font-style: italic;">fetch_all() -</code> run a SQL statement (typically a SELECT statement) and get back an arrayref of hashrefs (one hashref for each result row.)</li><br /><li> <code style="font-style: italic;">fetch_hash() - </code>run a SQL statement<code> </code>(typically a SELECT statement) and get back a single hashref (for just one row.)<code></code></li><br /><li> <code style="font-style: italic;">Do()</code> - run a non-SELECT statement such as <code>CREATE or <code>DELETE.</code></code></li></ul><code>DBIx::Wrapper::VerySimple</code> will use bind-variables if you pass them as additional arguments to <code style="font-style: italic;">fetch_all()</code>, <code style="font-style: italic;">fetch_hash()</code> or <code style="font-style: italic;">Do()</code>.<br /><br /><code>DBIx::Wrapper::VerySimple</code> also provides a <code style="font-style: italic;">get_args()</code> method and a <code style="font-style: italic;">dbh()</code> method. <code style="font-style: italic;">get_args()</code> returns the arguments originally passed to <code>new()</code> so you can re-connect, etc. if need be. <code style="font-style: italic;">dbh()</code> returns the raw <code>DBI</code> databse handle so you have ready access to all the features of <code>DBI</code>.<br /><br /><code>DBIx::Wrapper::VerySimple</code> is available on the CPAN: <a href="http://search.cpan.org/dist/DBIx-Wrapper-VerySimple/">http://search.cpan.org/dist/DBIx-Wrapper-VerySimple/</a><br /><br /><span style="font-size:85%;">Technorati tags: <a href="http://www.technorati.com/tag/CPAN">CPAN</a>, <a href="http://www.technorati.com/tag/DBI">DBI</a>, <a href="http://www.technorati.com/tag/Perl">Perl</a><br /></span>Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-8089710895956378772006-10-03T22:25:00.000-07:002006-10-03T22:29:00.319-07:00Perl::Metrics::SimpleCounts files, packages, subroutines, and calculates <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> of Perl files.<br /><br />I recently released an alpha version of new Perl module: <a href="http://search.cpan.org/dist/Perl-Metrics-Simple/">Perl::Metrics::Simple</a><br /><br />There is an included script, in the <span style="font-family:courier new;">examples/</span> directory which produces output like this:<br /><br /><pre><br />Perl Files: $file_count<br /><br />Line Counts<br />-----------<br />lines: $lines<br />packages: $package_count<br />subs: $sub_count<br />all main code: $main_stats->{lines}<br /><br />min. sub size: $lines{min} lines<br />max. sub size: $lines{max} lines<br />avg. sub size: $lines{average} lines<br />median sub size: $lines{median}<br /><br />McCabe Complexity<br />-----------------<br />min. main: $main_complexity{min}<br />max. main: $main_complexity{max}<br />median main: $main_complexity{median}<br />average main: $main_complexity{average}<br /><br />subs:<br />min: $complexity{min}<br />max: $complexity{max}<br />avg: $complexity{average}<br />median: $complexity{median}<br />std. deviation: $complexity{standard_deviation}<br /></pre>Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-45137232807451341762006-09-22T07:28:00.000-07:002006-09-22T07:38:56.533-07:00Ruby plug-in for EclipseI recently found out there is a <a href="http://www.ruby-lang.org/">Ruby</a> plug-in for the <a href="http://www.eclipse.org/">Eclipse IDE</a>: The "Ruby Development Tool."<br /><br />Quick install instructions:<br /><ol><li>Start up Eclipse.</li><li>Help > Software Updates > Find and Install...</li><li>Select "Search for new features to install"</li><li>Click "Next"</li><li>Click "New Remote Site..."</li><li>Enter the URL of stable release branch is: http://updatesite.rubypeople.org/release</li><li>Click "OK"</li><li>Click "Finish"</li></ol><a href="http://rubyeclipse.sourceforge.net/index.rdt.html">Ruby Development Tool (RDT) web site: http://rubyeclipse.sourceforge.net/index.rdt.html</a><br /><br /><a href="http://www-128.ibm.com/developerworks/opensource/library/os-rubyeclipse/">Article on using RDT: http://www-128.ibm.com/developerworks/opensource/library/os-rubyeclipse/<br /></a>Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-38940521298548948412006-09-03T18:14:00.000-07:002006-09-03T18:30:14.507-07:00Count Perl CodeI've started working on a module to analyze perl code report of files, lines, packages, subroutines, etc.<br /><br />A report could look like this:<br /><br /><pre><br /><span style="font-family:courier new;">% analyze.pl path/to/directory/of/perl/code</span><br /><br /><span style="font-family:courier new;">files: 39</span><br /><span style="font-family:courier new;">lines: 15929</span><br /><span style="font-family:courier new;">packages: 39</span><br /><span style="font-family:courier new;">subs: 336</span><br /></pre><br /><br />The module is (very tentively) named <span style="font-family:courier new;">Perl::Code::Analyze</span> and uses<br /><a href="http://search.cpan.org/dist/PPI/">Adam Kennedy's PPI module</a> for the real work.<br /><br />A (very) alpha version of the module is at<br /> <a href="http://g5-imac.matisse.net/%7Ematisse/Perl-Code-Analyze-0.01">http://g5-imac.matisse.net/~matisse/Perl-Code-Analyze-0.01</a><br /><br />Here's an example of a script that would use <span style="font-family:courier new;">Perl::Code::Analyze</span><br />to produce the report shown above:<br /><br /><code><br /><span style="font-family:courier new;">#!/usr/bin/perl</span><br /><br /><span style="font-family:courier new;">use strict;</span><br /><span style="font-family:courier new;">use warnings;</span><br /><span style="font-family:courier new;">use Perl::Code::Analyze;</span><br /><span style="font-family:courier new;">my $analzyer = Perl::Code::Analyze->new;</span><br /><br /><span style="font-family:courier new;">my $analysis = $analzyer->analyze_files(@ARGV);</span><br /><br /><span style="font-family:courier new;">my $file_count = $analysis->file_count;</span><br /><span style="font-family:courier new;">my $package_count = $analysis->package_count;</span><br /><span style="font-family:courier new;">my $sub_count = $analysis->sub_count;</span><br /><span style="font-family:courier new;">my $lines = $analysis->lines;</span><br /><br /><span style="font-family:courier new;">print <<"EOS";</span><br /><br /><span style="font-family:courier new;">files: $file_count</span><br /><span style="font-family:courier new;">lines: $lines</span><br /><span style="font-family:courier new;">packages: $package_count</span><br /><span style="font-family:courier new;">subs: $sub_count</span><br /><br /><span style="font-family:courier new;">EOS</span><br /><br /><span style="font-family:courier new;">exit;</span><br /></code>Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-86963556700715989762006-08-31T07:36:00.000-07:002006-08-31T07:43:17.356-07:00Apple releases Launchd as Open SourceApple has released their <a href="http://launchd.macosforge.org/">launchd</a> process manager under the <a href="http://www.opensource.org/licenses/apache2.0.php">Apache Open Source License</a> (version 2.0)<br /><br /><br />Launchd combines most of the features of the venerable Unix <a href="http://en.wikipedia.org/wiki/Cron">cron</a> and <a href="http://en.wikipedia.org/wiki/Init">init</a> facilities. You can use launchd to make sure a process is always running ("watchdogging"), to run jobs at specific times, to run jobs when/if a file appars in a specified directory, etc.<br /><br />I cover the basics of launchd in my book, "<a href="http://www.matisse.net/OSX/">Unix for Mac OS X Tiger</a>", and <a href="http://arstechnica.com/reviews/os/macosx-10.4.ars/5">ars technicha covers it</a> in their Tiger review.<br /><br />There is already a FreeBSD port of launchd.<br /><br />Macscripter.net has an <a href="http://macscripter.net/articles/440_0_10_0_C/">article describing how to use launchd with AppleScript to access a Flashdrive</a>.Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-26690602143125765742006-08-20T21:05:00.000-07:002006-11-02T06:29:45.058-08:00Mock Classes in Perl Unit Tests<span style="color: rgb(204, 0, 0);font-size:85%;" ><span style="font-style: italic;">UPDATE:</span><br /><span style="font-style: italic;">November 2, 2006: </span><a style="font-style: italic;" href="http://twoalpha.blogspot.com/2006/11/very-simple-wrapper-for-perl-dbi.html">I finally released the Wrapper module described here on the CPAN system</a><span style="font-style: italic;">.</span><br /></span><br />Today I added unit tests to a Perl module that uses the <span style="font-family:monospace;">DBI</span> module. My module, <span style="font-family:monospace;"><a href="http://search.cpan.org/dist/DBIx-Wrapper-VerySimple/">DBIx::Wrapper::VerySimple</a></span> is one that I wrote years ago.<br /><br />The tests use three tiny mock classes that take the place of the real <span style="font-family:monospace;">DBI</span> module. This allows the units tests to run in complete isolation from the actual <span style="font-family:monospace;">DBI</span> module.<br /><br />Back when I wrote DBIx::Wrapper::VerySimple wasn't experienced enough to bother creating unit tests for my code. These days I create unit tests any time I create a new module for a project and sometimes for scripts as well.<br /><br />The challenge in this case was that constructor method, <span style="font-style: italic; font-family: courier new;">DBIx::Wrapper::VerySimple->new()</span> calls <span style="font-family: courier new; font-style: italic;">DBI->connect()</span>, and I didn't want my unit tests to require connecting to an actual database. My solution is to have three tiny mock classes in my test code including a DBI.pm that the tests load before DBI::Wrapper can load the real DBI.pm.<br /><br />Here's what my mock DBI.pm looks like:<br /><pre><br /><span style="color: rgb(204, 0, 0);font-family:monospace;" ># Mock class - for testing only</span><span style="font-family:monospace;"><br /></span><span style="color: rgb(204, 0, 255);font-family:monospace;" >package</span><span style="font-family:monospace;"> DBI;<br /></span><span style="color: rgb(204, 0, 255);font-family:monospace;" >use</span><span style="font-family:monospace;"> strict;<br /></span><span style="color: rgb(204, 0, 255);font-family:monospace;" >use</span><span style="font-family:monospace;"> warnings;<br /><br /></span><span style="color: rgb(204, 0, 0);font-family:monospace;" ># warn 'Loading mock library ' . __FILE__;</span><span style="font-family:monospace;"><br /></span><span style="color: rgb(204, 0, 255);font-family:monospace;" >my</span><span style="font-family:monospace;"> $</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >MOCK_DBH_CLASS</span><span style="font-family:monospace;"> = '</span><span style="color: rgb(51, 0, 255);font-family:monospace;" >DBI::Mock::dbh</span><span style="font-family:monospace;">';<br /><br /></span><span style="color: rgb(204, 0, 255);font-family:monospace;" >my</span><span style="font-family:monospace;"> %</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >ARGS</span><span style="font-family:monospace;"> = ();<br /><br />sub connect {<br /></span><span style="color: rgb(204, 0, 255);font-family:monospace;" > my</span><span style="font-family:monospace;"> ( $</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >class</span><span style="font-family:monospace;">, @</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >args</span> ) = @_;<span style="color: rgb(204, 0, 255);font-family:monospace;" ><br /> my</span><span style="font-family:monospace;"> $</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >fake_dbh</span> = {};<br /><span style="font-family:monospace;"> bless $</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >fake_dbh</span><span style="font-family:monospace;">, $</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >MOCK_DBH_CLASS</span>;<span style="font-family:monospace;"><br /> $</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >ARGS</span><span style="font-family:monospace;">{$</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >fake_dbh</span><span style="font-family:monospace;">} = \@</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >args</span>;<span style="color: rgb(204, 0, 255);font-family:monospace;" ><br /> return</span><span style="font-family:monospace;"> $</span><span style="color: rgb(204, 0, 255);font-family:monospace;" >fake_dbh</span><span style="font-family:monospace;">;</span><br />}<br /><p face="monospace">1;</p><br /></pre><br /><br />My test script loads the mock DBI.pm and two other mock classes before <span style="font-family:monospace;">DBI::Wrapper</span> is loaded for testing. This way, when <span style="font-family:monospace;">DBI::Wrapper</span> is compiled my mock <span style="font-family:monospace;">DBI.pm</span> is used instead of the real one:<br /><br /><pre><span style="color: rgb(204, 0, 0);font-family:monospace;" ># Ensure that DBI::Wrapper loads our mock DBI.pm</span><span style="color: rgb(204, 0, 255);font-family:monospace;" ><br />use</span><span style="font-family:monospace;"> lib </span><span style="color: rgb(51, 0, 255);font-family:monospace;" >"$Bin/mock_lib"</span><span style="font-family:monospace;">;<br /></span><span style="color: rgb(204, 0, 255);font-family:monospace;" >use</span> DBI;<span style="color: rgb(204, 0, 255);font-family:monospace;" ><br />use</span> DBI::Mock::dbh;<span style="color: rgb(204, 0, 255);font-family:monospace;" ><br />use</span><span style="font-family:monospace;"> DBI::Mock::sth;</span><br /></pre><br /><br />This approaches works very well, and I was able to create unit tests that intercept all the calls that <span style="font-family:monospace;">DBI::Wrapper</span> makes that would normally go to the real <span style="font-family:monospace;">DBI</span>, and my intercepting these I can check that <span style="font-family:monospace;">DBI::Wrapper</span> is passing the expected values to DBI. I am deliberately <em>not</em> testing the real <span style="font-family:monospace;">DBI</span> module which has its own extensive set of unit tests. I merely test that my module will make the expected calls to <span style="font-family:monospace;">DBI</span>.<br /><br /><br /><strong>More about DBI::Wrapper<br /></strong><br />The module is available online at <a href="http://www.matisse.net/perl-modules/DBI/Wrapper/">http://www.matisse.net/perl-modules/DBI/Wrapper/</a><br />The version with the new unit tests is version 0.04.<br /><br />From the README:<br /><pre><br /><p style="text-indent: 20pt;"><span style="font-family:monospace;">DBI::Wrapper is a simple module that provides a high-level interface<br />to the Perl DBI module. The provided methods are for fetching<br />a single record (returns a hash-ref), many records (returns<br />an array-ref of hash-refs), and for executing a non-select statement<br />(returns a result code).<br /><br />The intention here is that your application will have much cleaner code,<br />so instead of writing:<br /><br />$sql = 'SELECT name,address FROM $table WHERE zipcode=?';<br />$sth = $dbh-&gt;prepare($sql);<br />$rv = $sth-&gt;execute($zipcode);<br />@found_rows;<br />while ( my $hash_ref = $sth-&gt;fetchrow_hashref ) {<br />push( @found_rows, $hash_ref );<br />}<br /><br />You would write:<br /><br />$sql = 'SELECT name,address FROM $table WHERE zipcode=?';<br />$found_rows = $wrapper-&gt;FetchAll($sql,$zipcode); # An array_ref of hash_refs</span><span style="color: rgb(0, 0, 255);font-family:monospace;" ><br /></span></p><br /></pre>I wrote the my version of DBI::Wrapper several years ago after I got the idea from a co-worker when I was doing a gig at TechTV.Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-1155222507842364312006-08-10T08:03:00.000-07:002006-08-10T08:08:28.030-07:00Compare BASIC, Ruby, Python, PHP, Perl, JavaScript, Lisp, False, Haskell etc.<a href="http://e-scribe.com/news/193" title="Comparing programming languages">Paul Bissex wrote three versions of a simple game, and posted it on E-Scribe news</a>: http://e-scribe.com/news/193<br />Readers have contributes more versions.Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-1149256452126438212006-06-02T06:50:00.000-07:002006-06-02T06:54:12.193-07:00Comparing Pair Programming to Solo ProgrammingBrian Slesinsky wrote recently <a href="http://slesinsky.org/brian/code/pair_versus_review.html" title="prefers pair programming to code reviews">comparing Pair Programming to Code Reviews</a> and argues that Pair Programming is better. I agree with his reasoning. I also think we need more hard-data on comparison of pairing vs. solo programming. It is a multi-dimensional issue, involving at least:<br /><ul><li>Total developer time spent.</li><li>Code quality and increase/reduction in the cost of product quality (more bugs == higher cost.)</li><li>Time-to-market. Two people spending 70 hours in parallel is faster to market than one person spending 100 hours.</li><li>Personalities and social dynamics. People have widely differing and strong held feelings about pairing vs. solo programming.</li></ul><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/agile" rel="tag">agile</a>, <a href="http://www.technorati.com/tag/extreme programming" rel="tag">extreme programming</a>, <a href="http://www.technorati.com/tag/pair programming" rel="tag">pair programming</a>, <a href="http://www.technorati.com/tag/programming" rel="tag">programming</a>, <a href="http://www.technorati.com/tag/code review" rel="tag">code review</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a>, <a href="http://www.technorati.com/tag/XP" rel="tag">XP</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-1149176183446968772006-06-01T08:33:00.000-07:002006-06-01T08:37:03.206-07:00How much eXtremism is too extreme?Blain Buxton recently wrote about <a href="http://blog.blainebuxton.com/2006/05/pair-programming-is-all-time-too-much.html" title="always pairing can be bad">how Pair Programming all the time could be bad</a>, and in general makes the case for not being extreme about being eXtreme.<br /><br />I think the most important point Blaine makes is that one should always be focused on what is best for the process, not on adhering to any particular technique.<br /><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/agile" rel="tag">agile</a>, <a href="http://www.technorati.com/tag/extreme programming" rel="tag">extreme programming</a>, <a href="http://www.technorati.com/tag/pair programming" rel="tag">pair programming</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a>, <a href="http://www.technorati.com/tag/XP" rel="tag">XP</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-1149093860377958672006-05-31T08:34:00.000-07:002006-05-31T09:44:20.426-07:00Pair-Programming Experiment at Stanford UniversityStanford University is in the middle of a formal experiment on <a href="http://www.pittsburghcorning.com/builders/newproducts_thickset.asp" title="http://en.wikipedia.org/wiki/Pair_Programming">Pair Programming</a>. I participated in the experiment this past weekend and had a lot of fun and, hopefully, helped advanced the state of knowledge about this controversial software development technique.<br /><br />A PDF document describing the experiment is available at <a href="http://hci.stanford.edu/research/pairs/PairProgramming-WhenWhy.pdf" title="http://en.wikipedia.org/wiki/Extreme_Programming">http://hci.stanford.edu/research/pairs/PairProgramming-WhenWhy.pdf</a><br /><br />The experiment is currently in the second ("Laboratory Experiment") phase as described in that document.<br />In the first phase ("Ethnographic Field Study") of the experiment the researchers visited two companies where pair-programming is regularly practiced and observed and recorded audio of programming pairs. These observations helped the researchers develop some hypothesis which may be checked by further work in the experiment.<br /><br />The researchers are focusing on the interaction between the people in the pairs (the "socio-cognitive factors" is how they say it.) The current phase of the experiment involves controlled tests where a pair of programmers or a solo programmer complete a warmup task and then a larger task (which takes around 5-6 hours all together.) The programmers are recorded via audio, video, and screen captures.<br /><br />During my pairing session this past weekend we talked a bit about the notion that once we humans have a goal we often have a strong impulse to start acting towards that goal, without necessarily doing much planning or testing - like driving nails before deciding where, exactly to drive the nails, and that we continue with our actions without doing much checking if we are in fact heading towards our goal. I don't think that Pair Programming stops individuals from having this impulse, but the presence of a second person makes it more likely, perhaps, that someone else will stop us. Hence my new joking slogan: "<strong>Pair Programming: It's not twice as smart, it's half as dumb!</strong>"<br /><br />Pair Programming as a formally recognized technique has been around for over a decade now, and as an informal reality I would guess it has been around for as long as there has programming. There has been only a little formal study of Pair Programming though, and Pair Programming is perhaps the most controversial technique in the <a href="http://en.wikipedia.org/wiki/Pair_Programming" title="http://en.wikipedia.org/wiki/Extreme_Programming">eXtreme Programming</a> methodology, touching as it does directly on people's self-image and personalities.<br /><br />I hope this experiment will help advance the state of knowledge about software development in general, and Pair Programming in particular, so that we can make better decisions about how to build things.<br /><br />The experiment is led by Robert P. Plummer, PhD., a Lecturer in the Stanford Department of Computer Science. Inquiries about the experiment can be sent to <strong>experiment at cs.stanford.edu</strong>.<br /><br /><!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: <a href="http://www.technorati.com/tag/agile" rel="tag">agile</a>, <a href="http://www.technorati.com/tag/extreme programming" rel="tag">extreme programming</a>, <a href="http://www.technorati.com/tag/pair programming" rel="tag">pair programming</a>, <a href="http://www.technorati.com/tag/programming" rel="tag">programming</a>, <a href="http://www.technorati.com/tag/software development" rel="tag">software development</a></p><!-- technorati tags end -->Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.comtag:blogger.com,1999:blog-13964332.post-1149088586898767242006-05-31T08:13:00.000-07:002006-05-31T08:16:26.970-07:00Test-Driven Development in the Physical WorldIt's occurred to me that we routinely practice Test Driven Development in the physical world, such as building houses.<br /><br />Consider how we use a "test first" approach in construction:<br /><br />Typically, if you want a hole in the wall 30 inches below the ceiling:<br /> 1. You take a ruler and make a mark on the wall 30" below the ceiling.<br /> 2. You drill a hole where the mark is.<br /> 3. If your hole is where the mark is/was, your test passes, otherwise, go to step 1.<br /><br />Now consider what that would be like without doing it "test first":<br /><br /> 1. You drill a hole in the wall.<br /> 2. You measure hole far from the ceiling the hole is.<br /> 3. If the hole is 30" from the ceiling, you win . Otherwise, go to step 1.Matisse Enzerhttp://www.blogger.com/profile/03736762585596345292noreply@blogger.com