Peter Stuifzand weblog

Inspired by the "Benificially Relating Elements" phrase of Kent Beck, I started out creating a builtin weblog for my webshop platform. The nice thing about the idea is that it helps you find relations between elements that you already have.

I started with the "What is a weblog?" A weblog is a chronological list of pages. By answering this way, I can reuse two elements that already are supported in the webshop: collections and pages.

Collections are lists of products and other collections. Nothing more nothing less. By increasing the scope of collections a little bit, I can also include pages.

A page is a piece of text that can be shown in the webshop. It has an url. By making a weblog post to be a page, I can reuse all the infrastructure of pages for weblog posts. This includes: creating, editing, saving and showing. The only thing missing from a page is the creation date, which is needed to sort the weblog posts chronologically.

The other two things that simplified the weblog feature are plug-ins and routes. Plug-ins are small packages of code that are loaded on start of the request and connect to rendering and loading and saving code.

Routes are ways to convert urls to controllers. The latest release made it possible to create routes based on regular expressions and all urls are parsed using this. This allowed me to use the names of the pages in the urls.

By relating the pieces, I created a new feature, that is useful in itself without having to write a lot of new code. Now when I add 'comments' as a feature to the weblog, I will also automatically add comments as a feature to pages, because they are the same thing.

Two features for the price of one. I like it.

The next feature I will talk about, is the given/when construct. This was added in perl 5.10. It works like switch/case in other programming languages, but is much more powerful. The matching is based on smart matching, which is another feature added in 5.010;

I will start with a simple example to give you an idea of the syntax that is used.

use 5.010;

my $x = <>;
chomp $x;

given ($x) {
    when ([0..99]) {
        say "Looking good";
    }
    when ([100..199]) {
        say "That's a bit much";
    }
    default {
        say "This could be a problem";
    }
}

This code compare the value of $x with the array's in the when statements. If $x is between 0 and 99 (inclusive) it will the text Looking good. If it's between 100 and 199 then it will say That's a bit much. The default block will be called when the value isn't matched by the when blocks.

Next I will give a more useful example, but not much more.

use 5.010;

my ($x, $y) = (0,0);

LINE: while (<>) {
    my @parts = split /\s+/;

    for (@parts) {
        when (/^x(\d+)/) {
            $x = $1;
        }
        when (/^y(\d+)/) {
            $y = $1;
        }
        when (/^p/) {
            say $x + $y;
        }
        when (/^q/) {
            last LINE;
        }
    }
}

This example reads lists of tokens from STDIN and matches them and executes code based on the input. In effect it's a small programming language. Notice that this code doesn't use the given statement. It's not needed here, because the for already assigns each element of @parts to $_.

It's also possible to use simple expressions like you would use in an if statement. For example:

use 5.010;

my $age = <>;
chomp $age;

given ($age) {
    when (!/^\d+$/) {
        say "Not a number";
    }
    when ($_ > 100) {
        say "That's quite old";
    }
    when (18) {
        say "Now your life begins...";
    }
    when (0) {
        say "Just born, and already using the computer.";
    }
    default {
        say "I have nothing useful to say about '$age'";
    }
}

As you can see when is quite smart about what to do with different expressions. The first when clause contains a negated regular expression. This will be matched using $age !~ m/REGEX/. The second one do what you expect. The 18 and 0 clauses will match using $age == 18 and $age == 0. You should watch out with comparing to 0 because this will also match empty strings or just strings. For example if $age = 'hello', when(0) will match.

Smartmatching is really powerful. With given and when it's easy to use this power for deciding what to do with the value that you've been given. You should take a look at the manual for more information about the possible smart matches and the things you can with given and when.

When I'm programming, I sometimes need to use a problem solving pattern, that Kent Beck called Parallel. The pattern tells us that when your making a change you should also leave the old way of doing things in the program, so you can gradually move to the new solution. This helps in situations, where you can't just flip a switch to migrate.

The problem with this however is, that you do have to migrate all the way to the new solution, because otherwise you will have twice the code and data in various states.

When I'm using Parallel, I like to keep an eye on the progress and I don't like to go back to the old way. To help me with this I created a unit test that monitors the progress that I make, while changing the program and the data.

It would be nice to have a test module that keeps track of this, but at the moment I only have a small test program. It does three things:

  1. Read the previous count (of old way occurences)
  2. Check if the current count is smaller or equal to the previous count.
  3. If true, the test succeeds and then writes the count to a file. If false, the test will fail.

This way the tests will only succceed if I make improvements or if the code stays the same. This way it can only improve the code.

Pasta and leeks

Example of how you should send email in 2010 with Perl.

#!/usr/bin/perl -w
use strict;

use Email::Sender::Simple qw(sendmail);
use Email::Simple;
use Email::Simple::Creator;

my $email = Email::Simple->create(
    header => [
        To      => '"Peter Foo" <foo@example.com>',
        From    => '"Peter Bar" <bar@example.org>',
        Subject => "What's up",
    ],
    body => "Hey, how are you doing?",
);

sendmail($email);

You can see that this is simple enough. First you create an Email::Simple object. This object will format the message that wil be sent.

After that sendmail will send this message using it's default transport.

The nice thing about using these modules is that you can, while testing, replace the default transport with testing modules.

use Test::More;
BEGIN { $ENV{EMAIL_SENDER_TRANSPORT} = 'Test' }
use YourModule;

YourModule->run;
my @deliveries = Email::Sender::Simple->default_transport->deliveries;
is(@deliveries, 1);

This way you can check how many emails were send using in the code your testing. By picking apart @deliviries you can check out the text of the emails that were send. See Email::Sender::Transport::Test for more information about this.

I use prove from Test::Harness to test the code of my Perl projects. The program prove runs tests files and summarizes the output. If tests fail then it shows the error in its output.

The problem is, my defaults aren't the same as the defaults that prove uses. I keep my main application files in app/lib and a few vendor libraries in vendor. The problem with this is that I have type out the options of prove every time I wanted to test. For the longest time I used a Makefile to solve this problem.

Then I found out about .proverc. If you put this file in your current directory of in your home directory, then prove will use each line as an extra command-line option.

The .proverc in the root dir of my project looks like this:

-Iapp/lib
-Ivendor
-r

It includes two extra directories in the Perl include path; app/lib and vendor. It also find all test files recursively in the t directory, which is also not a default setting of prove.

In the same way that Ubuntu has a list of problems that are trivially fixable Paper cuts, you could also do that for other programs. Google Buzz is a service that I use at the moment. I like this program, because it seems to take public standards into account and it will allow decentralized communication between people. So today I will spend some time to write down the few problems that I found that will be trivially fixable.

Ubuntu's definition is this:

a paper cut is a trivially fixable usability bug that the average user would encounter in default installation of Ubuntu or Kubuntu Desktop Edition*.

Paper cuts

  1. Muting a Buzz is very slow. This seems to be a problem with the fade. The thing is, it is nice that the Buzz fades away, but I don't need to see it. It should be fast. It also moves the viewpoint to the top. Please don't move my screen.

  2. Clicking a Buzz that isn't selected will move the screen to the start of the Buzz. If you scroll up from the next Buzz to a comment above in the previous Buzz, and then click on the comments, it will move the viewpoint to the start of the Buzz.

  3. The @-prefix for responding to people is ugly, when used with the domain name. There are better ways to do this. A few suggestions: '->', 'r:', '#', '>', '>>'. And I say screw backward compatibility and expectations.

So if you like the things I said here, please find a way to share it with some people. There seem to be quite a few places where that's possible today.

Jeff on Coding Horror writes:

Among programmers of any experience, it is generally regarded as A Bad Idea (tm) to attempt to parse HTML with regular expressions.

You should read the rest of the article. I'm mostly of the same opinion about this as Jeff. Additionally I think that parsing HTML is a bad idea in the first place.

One of the examples Jeff gives for parsing HTML is sanitizing user input. The user input will be used on the website as comments for example. I think allowing people to write HTML and putting it on a webpage is the wrong way to go.

If you want to include user input in a web page there are only two ways to do it:

  1. Encode all special HTML characters. You can start with <, >, &, " and '. If you encode these then people can send all the HTML they want, but it's encoded and will not affect your web page. For Perl I recommend the HTML::Entities module.

  2. The other way to allow HTML is, on a page, where it is their own. If they want to break their own web page, they should be allowed to do that. This doesn't mean profiles on websites, but actual websites that are completly their own.. So you say it is HTML and then use the input verbatim.

If you want to include some kind of formatting for the input, you can use a markup language. Use a markup language that allows to specify as much formatting as you like, this could be a HTML-like language, that only transforms the tags that you want. Therest of the text should be HTML encoded.

Adam Turoff wrote:

I could have written my taxicab number search in C or Java, but I would have lost interest somewhere between #include <stdio.h> or public static void main(String args[]) and firing up the compiler.

It's a shame this happens so often. It should be easier to just write the part your idea is about and then insert it into some thing, that will make the rest work.

Before being able to try and research your ideas, you need to have the basic code working. When people ask: why would you write your own X software? Where X is one of the pieces of software you have written, that looks like something that already exists. This would be the answer.

If there is a program or system that works for 95 percent or even 90, that would take a lot of time write. Then there is almost no incentive to create (or test) a similar tool. An example of this would be Google. Or a computer game that uses a 3D engine.

These all take many years to create, and there is not much to gain from the work that is done to get to the same level. To innovate you need to have a basis; but you will be bankrupt before you even get near.

A few days ago I started using Wave for some real projects. I found out that Wave is not really hard to use. The problem is that the network effect is kicking in, but in the opposite way.

Wave is a communication tool. You can use it to send messages and collaborate on projects with other people. And I think the problem here, is that the other people are missing.

I remember the first few years that I had internet. Not many friends were using email. I had email, but I had no one to send emails to. The same is happening with Wave now to. What use is it to send an email to someone, if you can't be sure that that person will read it.

I have a simple solution to this problem: install a Wave notifier. At the moment I use a notifier that works as extension in Chrome. It's non intrusive and shows a little number when I have new unread Waves. No interruption and I can take a look at the Wave that people sent me.

Wave me at peter.stuifzand@googlewave.com.