Debuggability-Driven Design

One of the pleasures of white-collar work is that you can earn money even while you're not on the job. Unlike a factory worker paid for each widget she assembles, a programmer or publisher or writer or business owner can sell widgets even when sleeping, or eating, or on vacation, or walking the dog.

Thank goodness for the automation of things like the cotton gin, the industrial revolution, the semiconductor, and the information economy.

The downside, of course, is that you have to trust these automations—and they're built by humans and programmed by programmers. (Worse yet, sometimes we are those programmers.) Things go wrong.

Our job is then to find and fix these bugs before the expense of lost potential automation overcomes the value of the automation.

Too bad we're lazy.

I built my own stock screener. It uses public APIs and public data to fetch financial data so that friends and family can make better investment decisions. I don't want them to have to fill out complex spreadsheets, and I don't want to type the right incantations to generate these spreadsheets. That means they get a little box on a web page and type in the symbol of a company and get an analysis later.

... unless they mistype the symbol name, or the company has been acquired, or it's moved between exchanges, or one of a dozen other things has gone wrong. For example, one API happily understands that Berkshire Hathaway has two classes of stock, trading under BRK.A and BRK.B, while another API goes into fits when it encounters a period in the name of a stock, and you have to call BRK.A "BRK-A" instead.

These are the cases where mock objects are no substitute for domain expertise.

The interesting cases are where you wake up on a Monday morning to find that something went wrong with several points of data over a long weekend and you're not sure what.

Sure, you could fire up your debugger, add in one of the offending symbols, and trace the process of API calls and analysis from start to finish, restarting the process as you try hypotheses until you reach an understanding, or at least have to get back to other work. I've done that. You can go a long way with that as your debugging technique.

Lately I begin to suspect that best practice patterns exist for batch processing projects like this. I've already realized that the process of a multi-stage analysis pipeline (first verify that the stock symbol exists; then get basic information like exchange, name, outstanding share count, sector, and industry; then analyze financial information like debt ratios, free cash flow, cash yield, and return on invested capital; then analyze current share price to projected and discounted share price) is, effectively, a state machine, and that by tracking the state of each stock in that state machine, you get both idempotent behavior (you'll never double-process a state, but you can restart a stock at any stage of the process by changing its state) and the ability to identify errors and bail out at any stage of the process (if a stock symbol doesn't trade on an associated exchange, you're not going to get any good information out of it, so avoid the CPU-expensive forward free cash flow projections, because they're useless; if a company's free cash flow trends negative, don't do the financial projections because you don't want to buy a company losing money and the numbers get asymptotically weird as you cross that zero line anyhow).

The real insight is that you should log the relevant information when an item in the pipeline hits an error condition. Sure, you can sometimes run into transient problems like a backhoe cutting fiber between you and your API provider such that your cron job won't get relevant data for a few runs, but you also run into the problem that what you expected to happen just didn't happen. That is, while you've been certain that the fifth element of the JSON array you get back from the request always contains the piece of information you expected, it never contains the information you want for companies in the finance sector, so you can't perform that analysis with that data source.

The real questions of automation are "What do you do when things go wrong?" and "How much information do you need to recover and to prevent these errors from occurring again?"

Maybe that means dumping out the entire API response. Maybe it means emitting the raw SQL query that caused a transaction failure. In my case it certainly means separating the process of fetching data from the process of processing data, so that I can load example data into my system without having to go through the fetching stage over and over again. (This experience of decoupling makes me prefer fixtures to mock objects.)

In my experience, it means that I can run a simple query:

> select count(*), state from stock group by state;
2413|ANALYZED
10|ERROR_DAILY_RATIOS
100|ERROR_UPDATE_BASIC

... to see that I have a few things to debug today, with fifteen dumps of API data in my basic_update_errors/ directory to review when I have a chance to see where my expectations (or the API documentation) has gone wrong.

In a sense, I've automated away half of the debugging process already: I have example data and I know where things go wrong. I know exactly where to look for the errors of assumptions. I don't know what those assumptions are, nor why they're wrong, but a computer probably couldn't tell me that anyway. Even getting halfway through this process means I'm twice as productive—I can focus my energy and concentration on the hard parts, not the tedious ones.

Perlbuzz news roundup for 2012-04-16

These links are collected from the Perlbuzz Twitter feed. If you have suggestions for news bits, please mail me at andy@perlbuzz.com.

  • K=R=P (Kindness = Repeat business = Profit) says @tom_peters. I say that for open source, K=U=G+S, Kindness = Users = Growth+Success.
  • You probably don't want to be using use_ok() (modernperlbooks.com)
  • Interpolate, concatenate or join? (perlmonks.org)
  • Quick-n-dirty tool to send messages to HipChat (blogs.perl.org)
  • Painless RSS processing with Mojo (blogs.perl.org)
  • RT @chromatic_x If you use SQLite for your CPAN distribution's tests, consider an in-memory database. Helps parallelism/Reduces disk IO.
  • Explaining web programming via Plack (blogs.perl.org)
  • Common Perl pitfalls (perlmonks.org)
  • Test::WWW::Mechanize adds scraping functions (perlbuzz.com)

Test::WWW::Mechanize adds scraping functions

The new 1.40 release of Test::WWW::Mechanize adds functions to help scrape text from your HTML as you test it. This should make things much easier for your integration test of your web apps.

For example, if you want to make sure that this shows up:

<h1>My awesome page!</h1>

then you can add an id attribute to the <h1>

<h1 id="pagetitle">My awesome page!</h1>

and your test can check for it:

$mech->scraped_id_is( 'pagetitle', 'My Awesome Page!' );

Two other functions are added to help in your text extraction: ->scrape_text_by_id() and ->scrape_text_by_attr().

Will these functions help your testing? Do you have other methods that you use to aid testing? As always, I welcome your feedback.

Draft raptor logo for NY.pm

Last summer, NY Perl Mongers (NY.pm), NY Perl Seminar and NY Perl Meetup agreed to unite under the NY.pm brand, using the old NY.pm mailing list for communications and the meetup.com website for event coordination. In addition to the social gatherings of the old NY.pm, the new NY.pm has added some technical talks, much like NY Perl Seminar used to have. We recently had an event-based programming talk, and in April, John Napiorkowski is presenting on Modern Perl and Moose.

Meetup.com wants a group logo and, for a long time, the NY Perl Meetup site used the Joe-Camel-esque Gnome2 Perl bindings mascot. Now that the Meetup.com site is for all NY Perl community activities, I though we should have a fresh logo that reflects a more Perlish (and less Gnomeish) identity.

Using kraih's open source Perl 5 raptor mascot/logo and a NY skyline image from DragonArtz Designs, I whipped up a draft of a new logo for NY.pm:

I'm not a graphic designer and I'm sure a professional would do better, but I think it will do for now until something better comes along.

I encourage other Perl Monger groups to do something fun with the Raptor — let's make it as widely known as the Camel and the Onion.

Source files for my logo work are available on Github: https://github.com/dagolden/nypm-logo

Mock Objects Despoil Your Tests

I don't know where this idea started in the testing world (I suspect Java, which makes the easy things possible, and the hard things a mess of XML and bytecode generation to work early static binding with the best type system 1969 and a PDP-7 had to offer), but if you find yourself wiring up a bunch of mock objects to test your system in isolation and pat yourself on the back for writing clever testing code, you'd better be lucky, because you're probably not testing your software well.

First, some philosophy.

Socrates: What's the purpose of testing your code?

Tester: To give us confidence that our software works as designed.

Socrates: How do you test?

Tester: Each piece in severe, bunny-suited, clean-room isolation.

Socrates: Why?

Tester: Because they must work in isolation.

Socrates: Does the system not work as a whole?

Tester: It does.

Socrates: How do you know?

Tester: Because we also test it as a whole.

Socrates: Does this give you no confidence in the correctness of the system?

Tester: No.

Socrates: Why not?

Tester: Because we only have a few tests of the system as a whole.

Socrates: Why? Surely the correctness of behavior and coherence of the system as a whole is important to the system as a project, else why would you be building it?

Tester: But unit tests are the most important tests. Someone somewhere once said so, and I have this really neat framework which generates mocks and stubs if I define the interface in my IDE and wire up the XML output.

Socrates: Does this give you confidence in your system as a whole?

Tester: Well, it's a real pain sometimes keeping the interfaces of the mock objects and their behaviors up to date as we change the code, but that's what a refactoring IDE is for, right? Sure, sometimes we have to add tests of the system as a whole because we find bugs, but you can't test everything to 100% anyhow, can you? Besides, we're using best practices.

Socrates: How do you test database interactions?

Tester: We use mock objects to simulate a database.

Socrates: Why don't you use a real database?

Tester: They're hard to set up and slow and we don't want to spend time debugging things like connection issues in our tests!

Socrates: How do you know your database code works?

Tester: Our mock objects work.

Socrates: When you go out to lunch as a team, do you go to a real restaurant and order food, or do you sit around in a circle pretending to eat sandwiches?

Tester: pantomimes being trapped in a glass box

(Pun mostly not intended.)

Yeah, I wrote a mocking library for Perl, many many years ago. Note well the short description:

Perl extension for emulating troublesome interfaces

I chose the word "troublesome" with care.

I almost never use this module, despite the fact that I wrote it. Sure, Perl and other late-bound languages with serendipitous polymorphism and allomorphic genericity make it easy to swap one thing in for the next if you can treat them as semantic equivalents. Yet in truth, mock objects are far, far overused.

In my experience, mock objects are most useful in very few circumstances:

  • When you want to test an exceptional condition it's difficult or expensive to produce (system error, external dependency failure, database connection disappearance, backhoe cuts your network cable).
  • When one tiny piece of an existing piece of code has a side effect you cannot easily control (the actual SMTP-over-a-socket sending of email, the actual purging of all of your backups, the actual adding of butterscotch chips to what would otherwise be a perfectly fine cookie recipe).
  • When you are utterly unable to control a source of information, such as data pulled from a remote web service (though you can design and test this with a layering strategy).
  • That's it.

I emphasize for clarity that that list does not contain "I am talking to a database", or "I am rendering an image", or "Here is where the user selects an item from a menu".

It's still important to be able to test your software in layers, such that you have a lot of data-driven tests for your data model and business logic without having to navigate through your UI in your tests, but the fact that you can automatically generate mock objects from your interfaces (or write them by hand, if you're using a language which doesn't require Eclipse to scale programmer effort beyond tic-tac-toe applets) doesn't mean that you should.

For example, one of my projects requires email verification of user registration. I have automated tests for this. One of them is:

    my $url = test_mailer_override {
        my $args = shift;

        $fields{USER_invitation_code} = '12345';
        $ua->gsubmit_form( fields => \%fields );
        $ua->gcontent_lacks( 'Security answers do not match' );
        $ua->gcontent_lacks( 'This username is already taken' );
        $ua->gcontent_contains( 'Verify Your Account',
            '... successful add should redirect to verification page' );

        my ($mailer, %args) = @$args;

        is $args{to}[0], 'x@example.com', '... emailing user';
        is $args{to}[1], 'xyzzy',           '... by name';
        my ($url) = $args{plaintext} =~ m!(http://\S+)!;
        like $url, qr!/users/verify\?!, '... with verification URL';
        $ua->gcontent_contains( 'User xyzzy created' );

        return $url;
    };

The function test_mailer_override() is very simple:

sub test_mailer_override(&)
{
    my $test = shift;

    my @mail_args;

    local *MyProj::Mailer::send;
    *MyProj::Mailer::send = sub { @mail_args = @_ };

    $test->( \@mail_args );
}

... where MyProj::Mailer is a subclass of Mail::Builder::Simple. This code temporarily monkeypatches my mailer class to override the send() method to record its arguments rather than performing an actual SMTP connection to my server. Not only does this run faster than it would if I had to wait for SMTP delivery before continuing the tests, but it avoids the need to set up a local mail server on every machine where I might run the tests or to hardcode mailer credentials in the test suite or even to need an active network connection to run the tests.

This makes the tests run quickly and gives me great confidence in the code. Furthermore, I know that on the real machines where I have this code deployed and running, the mail server and configuration works because I get real mail from it.

(I could as easily make my own subclass of my subclass which overrides send() this way and pass in an instance of that subclass through dependency injection. That would work well if I had to mock more than one method, but I haven't needed that yet and this localized monkeypatching was even easier to write and to maintain, so it serves me well enough for now.)

As for tests of database activity, I use DBICx::TestDatabase to create an in-memory test database for each test file in my suite. I have a batch of representative data carefully curated from real data to cover all of the important characteristics of my business model. I don't have to worry about any potential mismatch between data objects and mock objects and the real database because everything about my database is real except that it never actually exists on disk.

(If I had tests that care that it exists on disk—and I can only imagine a few reasons why I might—I would have stricter tests run on machines intended for production. If that's a concern, I'll do it. It's not a concern.)

I do understand the desire for mock objects and loose coupling and beautiful architectures of free floating components interacting briefly like snowflakes gently tumbling to a soft blanket on a Norman Rockwell Christmas landscape, but my code has to work correctly in the real world.

That means I have to have confidence that my systems hang together as working, coherent wholes.

That means that the details of what my tests do—their actions and their data—have a strong coupling to the behavior of my systems, because I have postulates and expectations to verify about those systems.

That means that I don't have time to duplicate behavior between real code and mock code, because I really only care if the real code works properly, and anything which distracts me from that, especially while debugging a failing test, is in the way.

That means that I will use mock objects sparingly, when I can't achieve my desired results in any cheaper, faster, or more effective way... but I won't mistake them for the real thing, because they're not.

use_ok() is Broken Because require() is Broken

Ovid's post on avoiding Test::More's use_ok() is good advice. There's almost no reason to use use_ok() from Test::More in existing code. It probably doesn't do what you think it does, and it doesn't really help against most of the failures you probably care about.

Worse, it can give you a false sense of security and mislead you into debugging the wrong thing.

Why? Because it turns what ought to be a fatal, program-killing exceptional condition ("Hey, I couldn't load this module! I'd better stop now. Things are certainly not going to work the way anyone expects!") into a simple failed test ("Oopsie! Better check your assumptions! I'll keep going though, because hopefully you just made a typo in your test assertion!").

The problem really isn't with use_ok() though. The problem's with Perl 5's require.

require does one thing. It searches the filesystem for the named file, compiles it, and caches the success or failure of compilation. (Make that three things.)

Here's the problem: what if compilation fails? What of compilation fails halfway through the file? What if compilation fails on the very last line of the file because the module doesn't return a true value? Try it yourself:

package FalseReturnValue;

sub demo { 'demo' }
sub demo2 { 2 }

0;

... and the test:

use Test::More;

use lib 'lib';
use_ok( 'FalseReturnValue' );

is FalseReturnValue::demo(), 'demo', 'Declared functions exist';
is FalseReturnValue::demo2(), 2,     '... all of them';

done_testing;

The problem is that failing to load a module should never leave your system in an inconsistent state.

Getting this right is very, very difficult. Getting this right means not committing anything to globally visible symbols until you're certain that the module compiled correctly. For a module like FalseReturnValue, that's easy. For a module which itself uses something like Catalyst or DBIx::Class with several dependencies, this is tricky.

The best approach I can think of is to maintain some sort of transactional system (yes, I know it sounds awfully complex, but you asked for correctness first, so humor me through at least this sentence) where you build up a set of changes to globally visible symbols and then only apply that delta if that compilation as a whole—the top-level module and all of its dependencies—succeeds.

The second best solution is to do that for each module. It's all or nothing for each use statement on its own, regardless of how far down the dependency tree you are.

(You could go one step further and make everything anonymous by default, such that the only way you can access package global symbols in another namespace is by binding to that namespace explicitly, but that's a bigger change with implications on code reuse and the cross cutting concerns of an object system, even though it does have the potential to clean up things like accidental exports.)

Of course, if your worldview has already said that failing to load a dependency with use should abort the program with red flashing klaxon lights and a siren, you don't have to do that much work.

(... but require errors are exceptions you can catch with eval { ... }, so the problem remains with require.)

Defending Against Its Dynamic Scope

A lot of the advice given in Modern Perl: the Book is advice learned the hard way, whether through making my own mistakes, debugging code written on my teams, or reviewing code written by other people to help novices become better programmers. After a decade-plus of this experience, I think I've developed a good sense of what people find confusing and what problems rarely occur in practice.

The pervasive use of global variables? It'll eventually catch up to you. Variables popping into existence upon use, not declaration? It'll cause problems far sooner than you ever expect.

Clobbering $_ at a distance inside a map block? It happened to me the other day. Yes, it surprised me too.

I've been attaching the Perl search bindings Lucy to a document processing engine. As part of the processing stage, my code adds documents to the search index. The index schema keeps track of specific fields, and it's denormalized slightly to decouple the document database from the search index. The code to add a document to the index creates a hash from method calls on each document object. That's where things started to go wrong:

sub add_entries
{
    my ($self, $entries) = @_;
    my $index            = $self->index;

    for my $entry (@$entries)
    {
        my $fields =
        {
            map { $_ => scalar $entry->$_() } keys %index_fields
        };

        $index->add_doc( $fields );
    }

    $index->commit;
    $self->clear_index;
}

I noticed things went wrong when my test bailed out with strange errors. Lucy was complaining about getting a hash key of '', the empty string. I was certain that %index_fields was correct.

While most of the methods called are simply accessors for simple object properties, these document objects have a method called short_content():

sub short_content
{
    my $self    = shift;
    my $meth    = length $self->content > $MIN_LENGTH ? 'content' : 'summary';
    my $content = $self->$meth();

    return unless defined $content;

    my $splitter     = Lingua::Sentence->new( 'en' );
    my $total_length = 0;
    my @sentences;

    for my $sentence ($splitter->split_array( $content ))
    {
        push @sentences, $sentence;
        $total_length += length $sentence;

        # must be a big mess, if this is true
        return $self->summary
            if  @sentences    == 1
            and $total_length > $MAX_SANE_LENGTH;
        last if $total_length > 0.65 * $MAX_LENGTH;
    }

    if (@sentences)
    {
        my $text = join ' ', @sentences;
        return $text if length $text > $MAX_SENTENCE_LENGTH && $text =~ /\S/;
    }

    return substr $content, 0, $MAX_SHORT_CONTENT_LENGTH;
}

A document may have a summary. It has content. short_content() returns a slice of the first significant portion of either, depending on which exists. While it's not the most detailed portion of the document, it's the earliest significant portion of the document, and it's demonstrably the best portion to index as a summary. (Thank you, inverted pyramid.)

The rest of this method attempts to break the short content at a sentence boundary, so as not to cut it off in the middle of a word or thought.

Nothing in that method obviously clobbers $_, but something called from it apparently does. (I wonder if Lingua::Sentence or one of its dependencies reads from a file or performs a substitution.) Regardless, I protected my precious hash key with a little defensive programming:

        my $fields =
        {
            map { my $field = $_; $field => scalar $entry->$field() }
                keys %index_fields
        };

... and all was well.

While this has been a very rare occurrence in 13+ years of Perl 5 programming, the trap is particularly insidious. The more work Perl does within that map block, the greater the potential for action at a distance. Furthermore, the better my abstractions—the more behavior hidden behind that simple method call—the greater my exposure to this type of bug.

Throw in things like dependency injection and Moose lazy attributes where you don't have to manage the dependency graph of your data initialization and flow yourself (generally a good thing) and you can't tell what's going to happen where or when.

If my instincts are correct, and something reads from a file somewhere such that only the first call to construct a Lingua::Sentence object clobbers $_, the point is doubly true.

(Sure, changing map to autolexicalize $_ would fix this problem, but it has backwards compatibility concerns for people who rely on this action at a distance—remember, it's only a problem if you write to $_—and it's too late to get such a change into Perl 5.16, even if it were only enabled with use 5.016;. Meanwhile, a variable assignment fixes it for me right now, and that will have to suffice.)

Perlbuzz news roundup for 2012-04-09

These links are collected from the Perlbuzz Twitter feed. If you have suggestions for news bits, please mail me at andy@perlbuzz.com.

  • The Perl Unicode cookbook (perl.com)
  • bdfoy's got some ideas for code (blogs.perl.org)
  • How @rjbs spent his Perl QA Hackathon (rjbs.manxome.org)
  • The homepage for ack is completely redesigned. Hooray for open source, making up for my lack of design skillz. (betterthangrep.com)
  • Tricks to compiling mod_perl 2 to OS X Lion (blogs.perl.org)
  • Have you seen perl-reversion? (blogs.perl.org)
  • Using WWW::Mechanize and mech-dump to get my scratchy 45s (perlbuzz.com)
  • DBD::Firebird releases v1.0 (firebirdnews.org)
  • Recap of the Perl QA Hackathon (dagolden.com)
  • Reading about what people are working on = happy. (blogs.perl.org)
  • Whatever task you have, it's probably already on CPAN (blogs.perl.org)
  • The Perl Foundation wants to give you money to work on Perl (news.perlfoundation.org)
  • More niche modules, "incredibly useful for about 5 people on earth": (github.com)
  • Did you know prove has --shuffle to run tests in random order? Has randomizing tests uncovered bugs for you?
  • MetaCPAN has a new logo (perlnews.org)
  • RT @dukeleto This is a huge step forward in #perl dependency management: "carton bundle" support! (github.com)
  • RT @aaronlerch Some devs think "I'll just copy and paste this code block." Now you have two problems. Now you have two problems.
  • Would love to see this Perl::Critic talk (blogs.perl.org)
  • "The Python site talks about the value the reader gets out of Python, while the Perl site talks about Perl" (modernperlbooks.com)
  • How to get ahead in open source: Wear sunscreen. (blog.nerdchic.net)
  • Help Open Source Bridge select session proposals (plus.google.com)
  • MetaCPAN at the QA hackathon (blogs.perl.org)
  • Perl Foundation helps fund critical Perl 5 dev (news.perlfoundation.org)

A Space For Thought

This is the text of a speech I gave recently for the International Speech Competition at my Toastmasters club. (I won the club competition and came second in the area competition a week or so later.)

I wrote early drafts in the first person, which I prefer to do for material rooted in personal experience, then changed it to second person as that seemed to be more effective in this case. In written form you’ll miss the gestures and delivery but hopefully the text is clear enough.

It’s written to spoken quite slowly (over 5 to 7 minutes), with lots of pauses, so please read it that way when you’ve some time to spare.

A SPACE FOR THOUGHT

Contest chair, fellow toastmasters and guests.

What is the difference between thought, and the quiet awareness in the gap between thoughts?

~pause~

Tonight, fellow toastmasters, I want to share with you the single most important thing I’ve learned in my life.

It’s a simple change in perspective that has revealed answers to many mysteries — so much more of the world makes sense to me now.

It’s a shift in how I relate to myself and the world around me,
that has brought great peace and joy into my life.

I really want to share this with you, but I have a problem.

The key idea is so simple that, if you’re not familiar with it, you probably won’t believe me.

Or if you are, you may dismiss it as obvious and of no value. Missing the depth and implications of it.

To persuade you I could quote countless great examples from literature, science, art, and everyday life.
Showing you how they fit together and make sense when viewed in this light.

But I don’t have time.

I only have time to give you a starting point, to plant a seed,
and some suggestions for how to nurture it, in the hope that it can grow and blossom for you too.

Before I give you this simple insight, before I plant this seed,
I need your help to prepare the ground.
I need you to experience something for yourself.

So please, do join me in a simple exercise in awareness. In paying attention.

Start paying attention now, to the feeling of your own breathing.
Maybe close your eyes, if you feel comfortable with it.
~pause~

Follow along with my instructions, and keep returning your attention to your breathing, till we’re done.
~pause~

Let your mind be quiet, and simply be aware the rising and falling of your belly.
Really notice what it feels like, maybe you can feel the movement of your clothes.
~pause~

The feelings you’re paying attention to are in your belly.
What you’re paying attention with is in your head.
~pause~

In a few moments I’ll say something to prompt some thought.
I want you to notice what happens to your attention when you start thinking.
Continue now paying quiet attention to your breathing.
~pause~

Green duck
~pause~

Did you notice your attention move away from your belly when you started thinking?
The focus of your awareness moved from your belly into your mind.

Your attention can’t be on a thought and something else at the same time.
You need to be aware of the thought, just as you need to be aware of the feeling.
Awareness is primary. Thinking and feeling are secondary.

~pause~

So here’s the seed I want to plant:

You are not your thoughts, just as you are not your feelings.

You, the essence of who you really are, is the awareness.

The conscious awareness within which your thoughts and feelings arise.

~pause~

That’s it.

It’s so simple, and yet so delicate.

Easily crushed by the weight of your own thoughts, that are constantly seeking to define you.

~pause~

Having planted the seed, I want to give you three tips for nurturing it, that I have found very helpful.

1st. Give your thoughts some space.

View them from a little distance.
Note their contents but don’t judge them.
Judging involves the thinking mind and you won’t break free.
Simply note their contents and let them go.

Treat your thoughts as suggestions from a much loved friend,
but a friend who you know is vain, insecure, and untrustworthy.

Noticing how this friend reacts to situations in your life
is a fascinating and rewarding pastime.
You don’t need to watch a soap opera on TV
when you can watch the one going on in your thinking mind!

2nd. Practice taking your attention away from thoughts
whenever they’re unhappy, unproductive or unhelpful.
Which, let’s face it, is much of the time.

Simply bring your attention to your breathing,
or anything else in the present moment.

3rd. Bring moments of stillness into your life regularly.

The phone rings — take a conscious breath with an empty mind before answering.
Get in the car — take a few breaths before starting the engine.
Look at nature, birds, trees, flowers, people,
without judging, labeling, or other thinking.

The more you do these simple things, the more your sense of self shifts,
from being lost in the noise and turmoil of the thinking mind,
to being rooted in the peace beyond it.

So I invite you to recognize your true self,
as not a bundle of thoughts and feelings,
but as the calm, peaceful, spacious, conscious awareness within which everything unfolds.


Filed under: health, life Tagged: toastmasters

Perl and that Dirty Word

To convince people to do something, you must first let them convince themselves that it is in their interest to do so.

Consider the first paragraph on Python.org:

Python is a programming language that lets you work more quickly and integrate your systems more effectively. You can learn to use Python and see almost immediate gains in productivity and lower maintenance costs.

If your concern is "getting stuff done" and "not painting yourself into a corner", all "in time and under budget", that's compelling.

Compare that to the first paragraph on Perl.org:

Perl 5 is a highly capable, feature-rich programming language with over 23 years of development.

That's an improvement over the old perl.org, but the Python text is more compelling.

(I'm open to the idea of adding good summary marketing text to the Perl.com homepage, but the entire site needs a theme overhaul. Anyone with Movable Type/Melody theming experience and some free time is more than welcome.)

When I wear my business hat, I usually do the copywriting for my businesses. This means the back cover copy and press release text and website blurbs for Onyx Neon books. This means the sales and marketing pages for Club Compy (site revision pending my business partner's new fatherhood of twins). This means even slogans and taglines such as "find the right price for stocks".

I know techies have a visceral reaction to the idea of "marketing" whereby we pretend to be shocked, stunned, and even offended that money might change hands. Filthy lucre! The immolation of Croesus! How dare you suggest that people talk about what's important to them, you lousy spammer?

Perception matters.

Perl has some huge advantages over other languages. Not every advantage is entirely exclusive, but if you were to start a new project in Perl today because one or more of these advantages were important to you, reasonable people would understand:

  • Perl is ubiquitous. It runs everywhere.
  • Perl is stable. Well-written programs will continue to run with little intervention.
  • Perl has a huge ecosystem in the CPAN. Most of your work is already done for you—freely usable, modifiable, and well tested.
  • Perl scales with your problems. It's suitable for small, quick programs as well as powerful, big-business programs.
  • Perl is flexible. It lets you do what you need to do and stays out of your way.
  • Perl is reliable. It has a huge test suite, a regular release cycle, and copious documentation.
  • Perl is easy to learn. (I wrote and give away and have committed to producing yearly revisions of Modern Perl: The Book to make this bullet point.)
  • Perl helps you create great software, with plenty of wonderful tools and libraries ready to help. (This is where Task::Kensho, Moose, Perl::Critic, Test::More, et cetera come in. Note carefully the place within the list.)

It's easy to extend this list to get more specific when the situation demands (though we tend to get too specific too fast; Catalyst isn't necessarily interesting to someone who really wants Bioperl, while DBIx::Class has little obvious value to a harried system administrator). It's nice to have a good place to start, though. Python has it right in two sentences. Perl needs a short blurb at least that good.

(Remember to keep in mind that the goal is to help people convince themselves that Perl will solve their problems—or help them realize that it's not what they need, while still reinforcing the image of Perl we want to express.)