<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>jroth</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/" />
    <link rel="self" type="application/atom+xml" href="http://blogs.perl.org/users/jroth/atom.xml" />
    <id>tag:blogs.perl.org,2009-11-03:/users/jroth//727</id>
    <updated>2011-03-30T16:57:20Z</updated>
    <subtitle>A blog about the Perl programming language</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.38</generator>

<entry>
    <title>(How would I) Moosify this!</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/2011/03/how-would-i-moosify-this.html" />
    <id>tag:blogs.perl.org,2011:/users/jroth//727.1603</id>

    <published>2011-03-30T02:31:37Z</published>
    <updated>2011-03-30T16:57:20Z</updated>

    <summary>In my previous post, I asked for critique and suggestions for a Moose alternative to my app&apos;s handrolled AUTOLOAD implementation of constructor attributes overriding same-named object methods, and constructor attributes overriding object proxy methods I asked, because this is the...</summary>
    <author>
        <name>Joel Roth</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jroth/">
        <![CDATA[<p>In my <a href="http://blogs.perl.org/users/jroth/2011/03/hand-rolled-oo-using-autoload-to-generate-audio-signal-processing-networks.html">previous
post</a>,
I asked for critique and suggestions
for a Moose alternative to my app's handrolled AUTOLOAD
implementation of</p>

<ol>
<li>constructor attributes overriding same-named object methods, and</li>
<li>constructor attributes overriding object proxy methods</li>
</ol>

<p>I asked, because this is the most complicated behavior of my
OO code, and would be a key issue in porting the code to
Moose. I also wanted to know if there would be other benefits
to using Moose for this app.</p>

<p>Unlike my earlier OO-related posts, no comments appeared.</p>

<p>After some days, Aristotle
<a href="http://blogs.perl.org/users/jroth/2011/03/hand-rolled-oo-using-autoload-to-generate-audio-signal-processing-networks.html#comments">replied</a>
that he believes my question was <a href="http://en.wikipedia.org/wiki/Warnock%27s_Dilemma">Warnock'ed
(ignored)</a>
because the description lacked specifics.</p>

<p>Here is my attempt to provide them. Since I'm not sure
exactly what to include and what to exclude, I'm
documenting the process of generating the signal
routing specification for a run of the Ecasound audio
engine.</p>
]]>
        <![CDATA[<h2>The big picture - a simple recording operation</h2>

<p>Say I have a project with three tracks: sax, piano, drums.
I want to record only drums, a mono signal, from the
soundcard channel 1. I set drums to REC. I set piano and sax
to OFF. Something has to happen before I can press START.</p>

<h2>Anatomy of a Track object</h2>

<p>Here are relevant attributes of the Track object:</p>

<pre><code>name: drums
class: Track
n: 3                   # unique integer index
group: Main            # bus affiliation
rw: REC                # could be REC, MON or OFF
source_id: 1           # input device ID, here the soundcard channel
source_type: soundcard # input device type
send_id: ~             # aux output device ID
send_type: ~           # aux output device type
width: 1               # number of channels in the input signal
</code></pre>

<h2>Routing considerations</h2>

<p>The 'drums' track belongs to Bus 'Main'. All tracks in Main
automatically provide a signal to the 'Master' track. Master
connects to the soundcard by default.  It serves as a mixer,
providing effects and a fader.</p>

<p>Each track has a raw (prefader) input signal as well as a "cooked" (postfader) signal that has undergone effects processing. Mono input signals get copied to allow for pan control and stereo monitoring.</p>

<p>To accomplish the routing and recording, we generate a file called a
'chain setup' that is used to configure Ecasound, the audio engine.</p>

<h2>The desired output - an Ecasound chain setup</h2>

<p>Here is the output we want:</p>

<pre><code># audio inputs

-a:1 -i:loop,Master_in
-a:3,R3 -i:alsa,default

# post-input processing

-a:3  -chcopy:1,2

# audio outputs

-a:1 -o:alsa,default
-a:3 -o:loop,Master_in
-a:R3 -f:s16_le,1,44100,i -o:/home/jroth/nama/test0329/.wav/drums_1.wav
</code></pre>

<p>In brief, each of the '-a' statements names one or more chains.
Each chain has one input and one output (specified by -i and -o).
Loop devices such as 'loop,Master_in' allow one chain to 
connect to another, one chain to have multiple inputs 
our outputs.</p>

<p>Track objects in Nama map to Ecasound chains. For the chain
setup, we use Track indices rather than names as
arguments to '-a'.</p>

<h2>Generating the routing graph</h2>

<p>To generate a chain setup, we first create a graph based on
the following:</p>

<pre><code>* the state of Tracks
* the state of Buses
* various global variables
* a specific user command
</code></pre>

<p>Here is the graph for this example:</p>

<pre><code>  x     soundcard_in            # endpoint (signal input)
  x     |          | 
  x   drums     drums_rec_file  # Tracks
  x     |          |
  x     |        wav_out        # endpoint (signal output)  
  x     |      
  x   Master_in                 # endpoint (loop device)
  x     |
  x   Master                    # Track
  x     |
  x   soundcard_out             # endpoint (signal output)
</code></pre>

<h3>Two observations:</h3>

<p>We have added a temporary track 'drums<em>rec</em>file' (an alias to
'drums') to provide a chain for recording the signal.</p>

<p>We have inserted a loop device 'Master_in' to 
be able to connect 'drums' to 'Master'.</p>

<p>When we create the graph, we may supply attributes
to the nodes or edges to control behavior of the back end.</p>

<p>For example, the chain_id for the edge (chain) corresponding  the
temporary track 'drums_rec_file' is set to 'R3',
overriding the default value (which would be the track index).</p>

<p>As another example, when a Bus routes a signal, it sets the
'send_type' and 'send_id' attributes in the graph because it
doesn't care about the track's own values for these attributes. </p>

<h2>Processing the Graph</h2>

<p>Now we are ready to process our graph. We want to use each edge 
of the graph to generate the lines of our chain setup.</p>

<p>We start with a dispatch() routine that creates an IO object
for each edge of the graph. The object then generates 
either an input clause (-i) or an output clause (-o).</p>

<p>The following output lists the class of each object
generated from the above graph, and the corresponding attributes
that dispatch() passes to the object constructor.</p>

<pre><code>Class: IO::from_soundcard_device
---
chain_id: 3
endpoint: soundcard_in
track: drums

Class: IO::to_loop
---
chain_id: 3
device_id: loop,Master_in
endpoint: Master_in
track: drums

Class: IO::from_loop
---
chain_id: 1
device_id: loop,Master_in
endpoint: Master_in
track: Master

Class: IO::to_soundcard_device
---
chain_id: 1
endpoint: soundcard_out
track: Master

Class: IO::from_soundcard_device
---
chain_id: R3
endpoint: soundcard_in
mono_to_stereo: ''
track: drums_rec_file

Class: IO::to_wav
---
chain_id: R3
endpoint: wav_out
mono_to_stereo: ''
track: drums_rec_file
</code></pre>

<h3>Discussion:</h3>

<p>The 'endpoint' maps to the class, and the class provides
methods to generate the output.</p>

<p>The track name is provided to enable the class to find
other attributes, such as signal width, or the
name of the output file.</p>

<p>Generally the input classes convert a mono signal
to stereo; we need to suppress behavior when
we are recording a signal. Hence we pass a
'mono_to_stereo' attribute that overrides
the output of eponymous object method.</p>

<p>As I write this, I can see that some override complexity
could be reduced by specifying whether the signal is a 'raw'
(prefader) signal or 'cooked' (postfader) signal.</p>

<p>There is flexibility from being able to pass attributes that
override the result of any object method. I could
potentially modify the methods to provide this 
behavior rather than use AUTOLOAD.</p>
]]>
    </content>
</entry>

<entry>
    <title>Using AUTOLOAD for object proxy and method resolution - Does Moose offer a better alternative?</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/2011/03/hand-rolled-oo-using-autoload-to-generate-audio-signal-processing-networks.html" />
    <id>tag:blogs.perl.org,2011:/users/jroth//727.1561</id>

    <published>2011-03-16T11:15:12Z</published>
    <updated>2011-03-30T17:50:30Z</updated>

    <summary>I&apos;ve written a couple articles on encapsulation issues in perl OO, especially with regards to home-grown versus full-framework OO. I am told that finding my own solutions to get the behavior I want may lead to poor (dirty, unreliable) code...</summary>
    <author>
        <name>Joel Roth</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jroth/">
        <![CDATA[<p>I've written a couple articles on encapsulation
issues in perl OO, especially with regards to
home-grown versus full-framework OO.</p>

<p>I am told that finding my own solutions to
get the behavior I want may lead to poor
(dirty, unreliable) code when a better solution
could come through a framework such as Moose.</p>

<p>I rolled my own perl OO for Nama, a <a href="http://freeshell.de/~bolangi/cgi1/nama.cgi/00home.html">multitrack audio recording app</a> I've written.  However,
I'm ready to consider introducing an OO framework for the
sake of learning, code quality, testing and maintenance.
Provided that I can find satisfactory ways to solve my problems.</p>

<p>Here's a laundry list of (just two) OO features that I'd
need or want to implement in a Mooselike framework.
One is short and simple to describe, the other will
take several paragraphs.</p>

<h1>Inheriting field definitions</h1>

<p>Track objects in Nama have 34 attributes, and are the
biggest class by far.  Track subclasses serve special
purposes that somewhat evident in their names: SimpleTrack,
CacheRecTrack, MixDownTrack, EditTrack, VersionTrack,
MixTrack. I've found it convenient to write the base class
so Track subclasses inherit attribute names from ancestor
classes.</p>

<p><strong>Update: I see this is default behavior for Moose</strong></p>

<h1>Object proxy and attribute overriding</h1>

<p>I'd read about AUTOLOAD for years, and wondered
what the fuss was about. With my home-grown OO,
I found I needed to use it.</p>

<p>Here is what I did.</p>
]]>
        <![CDATA[<h3>Problem domain - generating signal processing networks</h3>

<p>A lot of the complexity in multitrack audio production,
relates to routing, that is, creating signal processing
networks. Signals travel</p>

<ol>
<li>from sources such as audio files, soundcards or programs</li>
<li>through various components such as tracks and buses,</li>
<li>into sinks such as audio files, soundcards or programs</li>
</ol>

<p>Each recording or playback run requires an appropriate
network.  Nama doesn't perform audio processing itself; it
invokes the Ecasound audio engine, expressing the 
signal-processing network as an Ecasound chain
setup file.</p>

<p>Chain setups are made up of one or more signal chains. Each
chain has one input and one output. Intermediate nodes
called loop devices allow for summing or branching.
    Whenever needed or commanded by the user, Nama iterates over
all tracks and generates a routing graph. The graph is
implemented as a <a href="http://search.cpan.org/dist/Graph">Graph</a>
object whose nodes and edges may contain
attributes.</p>

<p>Nama traverses this graph to generate a set of IO
objects, each corresponding to the input or
output clause of an Ecasound chain. IO subclasses
correspond to each variety of input or output. To give one
example, an IO::wav_out object is used for writing a signal
to a WAV file. It creates a line such as:</p>

<pre><code> -a:2 -f:s16_le,2,44100 -o:Mixdown_2.wav
</code></pre>

<p>where "2" is the chain's ID, "s16_le,2,44100" is the signal
format, and "Mixdown_2.wav" is the output file.</p>

<p>Iterating over the IO objects generates the entire Ecasound
chain setup.</p>

<p>Generally attributes of the Graph node or edge will override
the methods of the corresponding IO object, but in some
cases methods have priority.</p>

<p>If an IO object doesn't have a particular attribute that one
of its methods needs, it looks to the corresponding Track
object (proxy relationship.)</p>

<h3>AUTOLOAD implementation described</h3>

<p>The way I currently implement this is as follows:
When constructing IO objects, each key gets an appended
underscore ("chain_id" becomes "chain_id_".)</p>

<p>Within the class definition, methods can be prefixed by an underscore to allow them to be overridden.</p>

<pre><code>package IO::wav_out;
sub _format_template { $raw_to_disk_format }
</code></pre>

<p>When resolving $io_object->format_template, since
format_template is not defined, the call is picked
up by the AUTOLOAD subroutine.</p>

<p>AUTOLOAD returns the object attribute
$io_object->{format_template_} if that key exists.</p>

<p>AUTOLOAD returns $io_object->_format_template if
that method exists.</p>

<p>AUTOLOAD returns $track->format_template if $track has
that method.</p>

<p>Otherwise AUTOLOAD throws an exception.</p>

<p>If the object has defined a method "format_template" (no
underscore) the call is resolved immediately. AUTOLOAD is
never invoked, giving the method definition the highest
priority.</p>

<h3>Discussion</h3>

<p>While this was an achievement to figure out and to debug, I
arrived at a clear design that meets my requirements.</p>

<p>I cannot say whether my solution is sufficiently general,
sufficiently robust, or represents appropriate use of
an appropriate hammer.</p>

<p>That is one reason I am writing this!  I would like to know
if I'm missing a better solution in the OO framework world.</p>

<h3>Code</h3>

<p>Here is code for the base class (with a few cosmetic changes)</p>

<pre><code>package IO;

our $AUTOLOAD;


# The template code below gets a comment-stripped list
# of attributes from the source file "io_fields" and appends
# an underscore to each key

use Object qw([% join " ",map{$_."_" }split " ", qx(./strip_all ./io_fields) %]);

# IO objects for writing Ecasound chain setup file
#
# Object attributes can come from three sources:
#
# 1. As arguments to the constructor new() while walking the
#    routing graph:
#      + assigned by dispatch: chain_id, loop_id, track, etc.
#      + override by graph node (higher priority)
#      + override by graph edge (highest priority)
# 2. methods called as $object-&gt;method_name
#      + defined as _method_name (access via AUTOLOAD, overrideable by constructor)
#      + defined as method_name  (not overrideable)
# 3. AUTOLOAD
#      + any other method calls are passed to the the associated track
#      + illegal track method call generates an exception

sub new {
    my $class = shift;
    my %vals = @_;
    my @args = map{$_."_", $vals{$_}} keys %vals; # add underscore to key

    # note that we won't check for illegal fields
    # to allow for AUTOLOAD resolution

    bless {@args}, $class
}
sub AUTOLOAD {
    my $self = shift;
    # get last part of method call
    my ($call) = $AUTOLOAD =~ /([^:]+)$/;
    my $field = "$call\_";
    my $method = "_$call";
    return $self-&gt;{$field} if exists $self-&gt;{$field};
    return $self-&gt;$method if $self-&gt;can($method);
    if ( my $track = $Track::by_name{$self-&gt;{track_}} ){
        return $track-&gt;$call if $track-&gt;can($call)
        # -&gt;can is reliable here because Track has no AUTOLOAD
    }
    print $self-&gt;dump;
    croak "Autoload fell through. Object type: ", (ref $self), ", illegal method call: $call\n";
}
</code></pre>
]]>
    </content>
</entry>

<entry>
    <title>Does breaking encapsulation indicate the wrong type of hammer?</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/2011/03/does-breaking-encapsulation-indicate-the-wrong-type-of-hammer.html" />
    <id>tag:blogs.perl.org,2011:/users/jroth//727.1557</id>

    <published>2011-03-15T07:30:13Z</published>
    <updated>2011-03-15T07:47:58Z</updated>

    <summary>I&apos;ve had the pleasure of exchanging several emails with Dave Rolsky, author of a new OO tutorial on the subject of whether to introduce treating objects as the underlying hash reference. He says he won&apos;t include even one example because...</summary>
    <author>
        <name>Joel Roth</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jroth/">
        <![CDATA[<p>I've had the pleasure of exchanging several 
emails with Dave Rolsky, author of a
new OO tutorial on the subject of whether to introduce treating objects as the underlying hash reference.</p>

<p>He says he won't include even one example because
"<em>it really doesn't send the right message. My revisions to  perlobj will explain how to implement accessors using the object as a hash reference.</em>"</p>

<p>I was shocked, because I find I <em>need</em> to visualize my
object's data structures.  Also, in several cases, reading
or writing attributes directly allows me to implement some
needed functionality.</p>

<p>I gave one example of this in a <a href="http://blogs.perl.org/users/jroth/2011/03/encapsulation.html">previous
post.</a>.</p>

<p>Dave suggested the reason I needed to break encapsulation
this way is that</p>

<ol>
<li><p>I haven't designed my objects properly or</p></li>
<li><p>I haven't taken advantage of a full OO
framework.</p></li>
</ol>

<p>He concludes that I'm using the same coarse
hammer to solve all my programming problems,
because I'm simply not aware of better
solutions.</p>

<p>Those are interesting criticisms.</p>

<p>The second point is absolutely right: I began my OO
experiment with Object::Tiny, adding a setter and other
facilities as I needed them. In fact, I am proud of this incremental
approach, admittedly chosen for my own learning.</p>

<p>Regarding the first point, "design smarts" for me is an
extremely limited resource.  So I substitute an iterative
process of problem-solving and refactoring. </p>

<p>Is it acceptable to use standard Perl tools for this, or
should I be reaching higher, tapping more advanced tools?
Suppose I had used Moose. Could I have solved my problems
easier, more elegantly, with less stumbling?</p>

<p>Well, for one I would have had to ask for help in the Moose
community, whereas with hand-rolled OO, I can understand the
entire codebase, even if it doesn't meet certain standards
of tidiness, design or even hygiene.</p>

<p>On the other hand, I do want my code to be beautiful, for
various aesthic reasons, for ease of testing and
maintenance, and also to have a code base that will be
sufficiently attractive to other people to hack on.</p>

<p>With the aim of exploring whether I can achieve something
better using Moose, Mouse, Moo or other advanced
framework, in my next post, I'll give an example of some
of my more advanced needs, and the naive, if not neolithic
ways I implemented them. </p>
]]>
        

    </content>
</entry>

<entry>
    <title>Encapsulation: recommended practice or sacred cow?</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/2011/03/encapsulation.html" />
    <id>tag:blogs.perl.org,2011:/users/jroth//727.1548</id>

    <published>2011-03-12T21:40:33Z</published>
    <updated>2011-03-12T21:59:38Z</updated>

    <summary><![CDATA[In the p5p discussions of Dave Rolsky's new Perl OO tutorial and OO recommendations, Johan Vromans and others have mentioned that in good OO programming, one should not violate encapsulation by directly accessing an objects underlying data structure. $self-&gt;{foo} =...]]></summary>
    <author>
        <name>Joel Roth</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jroth/">
        <![CDATA[<p>In the p5p discussions of Dave Rolsky's new Perl OO tutorial and OO recommendations, Johan Vromans and others have mentioned
that in good OO programming, one should not violate encapsulation by directly accessing an
objects underlying data structure.</p>

<pre><code>$self-&gt;{foo} = "Look Ma! No encapsulation"; # don't do this, they say
</code></pre>

<p>In general that is true, but not always, We should avoid absolutist language, especially in tutorials. I'll come to an example of that.</p>

<p>For Nama, I generally use a setter with this syntax:</p>

<pre><code>$self-&gt;set(foo =&gt; "bar");
</code></pre>

<p>The set method (inherited from a parent class based 
on Object::Tiny) makes sure the key is a legal one.</p>

<p>Because it looks distinct, I'm not likely
to use it unless I want really write access to that attribute.</p>

<p>This simple approach allows me to manage object attributes culturally, i.e.
without specifying them as read-only or read-write.
In an app of 13k lines, the 'set' method appears just 110 times.</p>

<p>But it's still possible to directly modify an object
in other ways:</p>

<pre><code>my $self = Object-&gt;new( foo =&gt; [qw(this is a pen)] );
my $array_ref = $self-&gt;foo;
$array_ref-&gt;[3] = 'lobster'; 
print $self-&gt;as_string # "this is a lobster"
</code></pre>

<p>I am living with that.</p>

<p>The other point is that I believe there can be legitimate
reasons to violate encapsulation. I recently found a good example. <a href="http://freeshell.de/~bolangi/cgi1/nama.cgi/00home.html">Nama</a> allows you to create
a new track object that refers to WAV files 
with a basename other than the track's own name.</p>

<p>For an ordinary track, the name matches the WAV file:</p>

<pre><code>my $Mixdown = Track-&gt;new( name =&gt; 'Mixdown'); # associates with Mixdown.wav
</code></pre>

<p>Here is a track created by the 'link_track' command,
that also associates with Mixdown.wav.</p>

<pre><code>my $song = Track-&gt;new( name =&gt; 'song', target =&gt; 'Mixdown');
</code></pre>

<p>Here is a track created by the 'new_region' command, 
that indirectly associates with the same file.</p>

<pre><code>my $final_song = Track-&gt;new( name =&gt; 'final_song', target =&gt; 'song' )
</code></pre>

<p>Here is the code I use so that $final_song->target returns
'Mixdown':   </p>

<pre><code>package Track;

sub target {
    my $self = shift;
    my $parent = $Track::by_index{$self-&gt;{target}};
    defined $parent &amp;&amp; $parent-&gt;target || $self-&gt;{target};
}
</code></pre>

<p>Now there could be some discussion about my using the track
name (as opposed to a Track object) as the value for the
'target' field.  In short, this design decision has made it
easy to serialize and to debug by dumping objects as YAML.</p>

<p>Regarding encapsulation, the point is that accessing $self->{target} is 
essential for this code to work.</p>

<p>Accessing the underlying hash provides the behavior I want.</p>

<p>I think it's simplistic to assume that every new user
could or should find other ways to achieve this behavior
<em>without</em> violating encapsulation.</p>

<p>Our tutorials should respect readers' intelligence.
I think we can tell them what is good practice, without
prescribing an idealistic straitjacket.</p>

<p>Even if I'm missing an easy solution that doesn't access the
hash, why should I be required to find one?</p>

<p>For example, I could do it this way:</p>

<pre><code>package Track;

sub _target{ $_[0]-&gt;{target} }

sub target {
    my $self = shift;
    my $parent = $Track::by_index{$self-&gt;_target};
    defined $parent &amp;&amp; $parent-&gt;target || $self-&gt;_target;
}
</code></pre>

<p>But the code is no clearer and the first line still
violates encapsulation.</p>

<p>I can see the importance of respecting encapsulation in
large projects using others' OO libraries, but not all use
cases fall into that category.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>A Novice Refactors</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/2011/03/a-novice-refactors.html" />
    <id>tag:blogs.perl.org,2011:/users/jroth//727.1541</id>

    <published>2011-03-09T21:48:33Z</published>
    <updated>2011-03-09T23:19:57Z</updated>

    <summary>Having read commentary about coding practices, meditated, contemplated, posted a blog entry about my app and begged for constructive criticism, I found my way into a significant refactoring. I haven&apos;t seen much about the step-by-step process of dividing and modularizing...</summary>
    <author>
        <name>Joel Roth</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jroth/">
        <![CDATA[<p>Having read commentary about coding practices, meditated,
contemplated, posted a <a href="http://blogs.perl.org/users/jroth/2011/02/architectural-review-board---please-visit-my-project.html">blog entry</a> about my <a href="http://freeshell.de/~bolangi/cgi1/nama.cgi/00home.html">app</a> and begged
for constructive criticism, I found my way into a significant
refactoring.</p>

<p>I haven't seen much about the step-by-step
process of dividing and modularizing code.
Here how I am approching it.</p>

<p>The app already uses OO, but suffers from some 260 global
variables and about 6k lines of code in the main namespace.</p>

<p>I broke that code into about 30 different modules, testing
after creating each new module, with the help of git for
source control, and a couple scripts showing which files and
in which subs each variable appears</p>

<p>Most modules still occupy the same namespace,
however have access to only the minimum necessary subset of
global variables. I did this using a structure like this:</p>

<p>[Audio_engine_setup.pm]</p>

<pre><code> package main;
 our ( $sampling_frequency,.... )
 sub configure_freq { say "configuring soundcard at $sampling_frequency" }
</code></pre>

<p>All subroutines are still in the main namespace, so
they work unchanged.</p>

<p>The 'our' declaration tells me exactly what global variables
the module touches. So I can look at them and think: Do they
need to be in the main namespace? Can they be lexicalized?
Can they be passed as arguments?</p>

<p>A next step is to provide more separation by introducing a
separate namespace.</p>

<pre><code>  package main;
  our ( $sampling_frequency,....)
  package Audio_engine_setup;
  sub report_freq { say "soundcard is running at $sampling_frequency" }
</code></pre>

<p>These subroutines (and those in the main namespace they
invoke) will have to be called with the full
package affiliation, or be imported into the desired
namespace via Exporter and 'use', or be converted to use
some kind of OO.</p>

<p>Physically reorganizing the code provides an opportunity to
partition functions, to define interfaces and to review
provisional design decisions made years ago.  Of course
greater separation of concerns helps the software to be
robust and to be readable.  And having the code divided up helps anyone who
wants to browse/hack.</p>

<p>How much separation is desirable practical is an open
question.  Most global variables are indices or
configuration variables that are set once and read-accessed.
Yes, anywhere it's possible to set them by accident. On the other hand, this is
a single app, not a toolkit that will be (ab)used by other
programs in an adverse environment.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Architectural Review Board - Please visit my project!</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/2011/02/architectural-review-board---please-visit-my-project.html" />
    <id>tag:blogs.perl.org,2011:/users/jroth//727.1500</id>

    <published>2011-02-24T01:56:19Z</published>
    <updated>2011-02-24T02:27:25Z</updated>

    <summary>I&apos;ve been writing and rewriting Nama[1,2,3] for several years now. It&apos;s been my introduction to intermediate concepts in computer science. Nama is an audio recording, mixing and editing application, using Ecasound[4] as the audio engine. I&apos;m proud of how it...</summary>
    <author>
        <name>Joel Roth</name>
        
    </author>
    
    <category term="audio" label="audio" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jroth/">
        <![CDATA[<p>I've been writing and rewriting Nama[1,2,3] for several years now. It's been my introduction to intermediate concepts in computer science.</p>

<p><strong>Nama is an audio recording, mixing and editing application</strong>, using Ecasound[4] as the audio engine.</p>

<p>I'm proud of how it has evolved.  At first it was all procedural, driven by a command processor loop. Then I added a Tk-based GUI, my first GUI.  I added a text interface with a command grammar based on Parse::RecDescent.  I introduced OO to separate the code for two different UIs.  Then I added classes for tracks, buses and other entities.  I added an event system (actually two), serialization, a help system, tests. I created a build system to automatically generate parts of the grammar, the help system, and to merge various files. The code for audio routing has gone through three different design interations: hardcoding, routing by rules, and now, routing by creating and transforming a graph.</p>

<p>I've cleaned up, commented, refactored wherever it could help. I profiled and memoized to speed up my code.  I refer to a shelf full of well-respected Perl books, follow PerlMonks and other forums of the Perl community.  Most of the <em>really</em> hard stuff I've solved by accreting other programs and libraries, largely from CPAN.</p>

<p>It's been exciting, exhiliariating, and at times laborious, confusing and opaque. I've had users helping to test, suggest features, and occasionally hold my hand.</p>

<p>Despite all my work to keep the code legible, even users familiar with perl have a hard time reading the code. I'm feeling ready for a visit by the architectural review board!</p>

<p>After reading a number of articles advising against the use of global variables. I'm wondering: Should I be encapsulating the 250 or so global variables into objects? (Clearly, yes.)</p>

<p>What about the way classes reach into each other for data?</p>

<p>Maybe I should be re-architecting my tests? Expanding test coverage is hard, but necessary. I'll need a way to build a test environment that includes (or fakes) some WAV files and other project data.</p>

<p>Welcome, ARB, especially those of you who are musicians!</p>

<ol>
<li><a href="http://github.com/bolangi/nama">Nama - github</a></li>
<li><a href="http://search.cpan.org/dist/Audio-Nama/">Nama - cpan</a></li>
<li><a href="http://freeshell.de/~bolangi/cgi1/nama.cgi/00home.html">Nama - home</a></li>
<li><a href="http://eca.cx/ecasound/">Ecasound</a></li>
</ol>
]]>
        

    </content>
</entry>

<entry>
    <title>Using external installers with CPAN Clients</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jroth/2011/02/using-external-installers-with-cpan-clients.html" />
    <id>tag:blogs.perl.org,2011:/users/jroth//727.1485</id>

    <published>2011-02-19T04:56:23Z</published>
    <updated>2011-02-20T04:20:07Z</updated>

    <summary>A lot of work is currently underway to improve CPAN. One longstanding issue is the handing of external dependencies (the &quot;libfoo&quot; problem.) As I understand it, although CPAN distributions may test for external dependencies, existing build tools are unable to...</summary>
    <author>
        <name>Joel Roth</name>
        
    </author>
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jroth/">
        <![CDATA[<p>A lot of work is currently underway to improve CPAN.  One
longstanding issue is the handing of external dependencies
(the "libfoo" problem.) As I understand it, although CPAN
distributions may test for external dependencies, existing
build tools are unable to install non-perl libraries, header
files or compilers.</p>

<p>Resources to solve these problems <em>are</em> available, but in
places not usually considered by CPAN toolmakers.  I'm
referring to <i>native OS package repositories.</i> While
natively packaged CPAN distributions necessarily lag current
CPAN offerings, they meet non-perl as well as perl
dependencies, and are generally troublefree to install.</p>

<p>To give the example I know best, Debian's perl repository
covers roughly 10% of CPAN, including much of CPAN's best.
This enormous investment in labor, <a
href=http://pkg-perl.alioth.debian.org/cgi-bin/pet.cgi>
toolchain development </a> and community building results in
high-quality packages that even new users can install
easily.</p>

<p>As a developer of a <a
href=http://search.cpan.com/dist/Audio-Nama>perl audio</a> <a
href=http://freeshell.de/~bolangi/cgi1/nama.cgi/00home.html>
application</a> <a
href=http://packages.debian.org/squeeze/nama> available for Debian</a>,
I've encountered problems managing dependencies when
administering systems that mix distro and CPAN sources, even
when using local::lib.</p>

<p>One issue is that CPAN clients will always fulfill a
distribution's dependencies from CPAN, even if native
packages are available.</p>

<p>I'd like to suggest a small but significant step to bridge
this divide between native and CPAN repositories: a native
installer option for CPAN clients. </p>

<p>After a few false starts, here's a working demonstration: a
<a href=http://github.com/bolangi/cpanminus-distro> patched
version of cpanminus </a> that supports multiple native
installers.   </p>

<p>You can invoke it like this:</p>

<pre><code>cpanm --distro Debian Some::Module
</code></pre>

<p>causing cpanm to execute:</p>

<pre><code>$distro_installer = eval {require "CPAN::NativeInstaller::Debian" }
</code></pre>

<p>$distro_installer then gets a chance to provide a native
package for each distribution cpanm seeks to install.
With this added ability, CPAN client users can install perl
distributions from both native and CPAN repositories, and
finesse the libfoo problem for a significant
portion of CPAN.</p>

<p>What better way to encourage the resurgence in perl
popularity than to help application developers
administer their systems?</p>
]]>
        

    </content>
</entry>

</feed>
