Saturday, January 23, 2010

Maven, the new Elephant on the Block

Some of you may remember the article, by Bruce Tate, Don't Make Me Eat the Elephant Again.
It was an article about EJB, and Bruce was begging Sun not to make the same mistakes with EJB3 as they had done with EJB, and EJB2. They didn't, Spring came along as better alternative and forced EJB3 to become slimmer and better. If not for Spring, EJB3 would probably look very different from what it looks like today.
Well, guess what, there is a new elephant on the block and its name Maven2.


Just like EJB2, Maven2 was born out of something so unbearable that anything else was bliss. Jelly anyone!


But just as EJB was fundamentally flawed, so is Maven2. Build systems, even advanced ones like Maven is fundamentally about two things.
  1. Check if something that something else depends on has changed
  2. If so, do something.
That's it, that is what is important.
The checking may contain various sophisticated methods for detecting if files, subsets of files, all files, web pages, twitter feeds, etc, has changed, but that is really it.
And the doing can be anything, Copy files, commit files, build websites, run tests, generate code, launch missiles, whatever!
But the key to doing this efficiently is a programming language with easy access to system commands and the ability to create simple abstractions, with methods, variables, and objects. The language should also, preferably, be one without a lot of ceremony, like Ruby, Javascript or Python.
There are already build systems like this out there, Buildr, SCons, and Rake come to mind, but they do not have the momentum of Maven, so a merger between Maven and Buildr would be wonderful.



So, Jason, hear my plea, Don't make me eat the elephant again!

Saturday, January 16, 2010

Scripting in Ruby

I just read, or rather skimmed, the book, called Everyday Scripting with Ruby and it is awful. I had high expectations. I was expecting something like Perl for System Administration, where you right away get into hard core Perl scripting. This book is nothing like that! It is a really basic introduction to Ruby, and if you have any experience programming at all, DON'T BUY THIS BOOK.

OK, enough complaining! I am going to do what this book does not do. I am going to show a good way to write scripts in Ruby. If you want to learn more about Ruby, buy Programming Ruby, The Well-Grounded Rubyist and The Ruby Way.

Ruby is an excellent language. It is, in my opinion, the best scripting language and it beats both Perl and Python face down. If you are not scripting in Ruby, you are missing out. Ok, so here is the script.

sendgmail

The script is called sendgmail and it sends mail via gmail (surprise!).

This is how the command is used.

$ sendgmail --help
/usr/local/bin/sendgmail [options] attachments...
Options are ...
    -t, --to TO                      Send email to recipient
    -m, --message MESSAGE            Include the message.
    -s, --subject SUBJECT            Include the subject.
    -v, --verbose                    Log to standard output.
    -V, --version                    Display the program version.
    -h, -H, --help                   Display this help message.

And here is the code, liberally sprinkled with comments.


#!/usr/bin/env ruby
# Use the currently configured ruby version

# optparse contains OptionParser, ostruct: OpenStruct and growl Growl
require 'optparse'
require 'ostruct'
require 'growl'

# This is the name of the script that is called
# Whatever you name your script will be reflected here.
# This can be useful if you want to have the same script do many things
# Create differently named links to the script 
# and use the program name to select behavior.
PROGRAM_NAME = $0
PROGRAM_VERSION = 1.0

# Create an OpenStruct to save the options.
# OpenStruct allows you to use options.my_option instead of 
# option['my_option'] with a normal hash
# http://ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/OpenStruct.html
def options
  @options ||= OpenStruct.new
end


# This is the options of the program, see OptionParser
# http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
def program_options
  [
          # The values of the array are,
          # [long_option, short_option and parameter, description, code to execute]          
          ['--to', '-t TO', "Send email to recipient",
           lambda { |value| options.to = value }
          ],
          ['--message', '-m MESSAGE', "Include the message.",
           lambda { |value| options.message = value }
          ],
          ['--subject', '-s SUBJECT', "Include the subject.",
           lambda { |value| options.subject = value }
          ],
          ['--verbose', '-v', "Log to standard output.",
           lambda { |value| options.verbose = true }
          ],
          ['--version', '-V', "Display the program version.",
           lambda { |value|
             puts "#{program_name}, version #{PROGRAM_VERSION}"
             exit
           }
          ]
  ]
end

option_parser = OptionParser.new do |opts|
  opts.banner = "#{PROGRAM_NAME} [options] attachments..."
  opts.separator ""
  opts.separator "Options are ..."

  # Add the command on_tail, to make it appear as the last option in the list.
  opts.on_tail("-h", "--help", "-H", "Display this help message.") do
    puts opts
    exit
  end

  program_options.each { |args| opts.on(*args) }
end

begin
  # Parse the options and remove them from the ARGV array
  option_parser.parse!
rescue OptionParser::ParseError => error
  puts error.message
  puts option_parser
  exit
end

unless options.to
  puts 'Missing required argument --to or -t'
  puts option_parser
  exit
end

options.subject = 'No subject' unless options.subject
options.message = '' unless options.message

# Concatenate the options into a proper command
command = 'sendemail -o tls=yes -s smtp.gmail.com -f from@gmail.com -xu from@gmail.com -xp secret'
command += "-t '#{options.to}' -u '#{options.subject}' -m '#{options.message}' "

# Append the filenames with the -a option to send them as attachments
# Only the non options (the filenames) are left in ARGV
unless ARGV.empty?
  command += " -a #{ARGV.join(' ')}"
end

# Print the command to screen if using verbose mode.
puts command if options.verbose
system command

Growl.notify "#{options.subject}\n#{options.message}", :icon => :jpeg, :title => "Email sent to #{options.to}"

The script requires you to install sendemail. It also requires you to install the growlnotify command line utility that is distributed with Growl and the gem that uses this utility, also conveniently named growl.

Install required dependencies on OS X


# Install sendemail and capabilty to send secure mail, required by Gmail
sudo port install sendemail p5-net-ssleay p5-io-socket-ssl

# Install growl command utility from the mounted image
sudo sh /Volumes/Growl-1.2/Extras/growlnotify/install.sh

# Install the growl gem
sudo gem install growl

That’s it, a simple script that will allow you to send messages and files through
gmail from the command line.

Friday, December 11, 2009

Why #twitter sucks!

The problem with Twitter is information overflow. The reason for this overflow can be summarized with one simple sentence.

What are you doing right now?

That sentence opens up a whole can of worms.

It is totally egoistic. "What are you doing right now?", doesn't say that, what you are writing should, preferably, be interesting to someone else than you.

It doesn't say: You are sharing this with the rest of the world and you should at least think twice before you write "I am eating a donut".

"Right now", is devastating. It encourages you to write something without thinking. If it was to be taken literally, "I am publishing an uninteresting message on Twitter" would be the content of 90 percent of the tweets.

One thing it does not say is "Let's have a public dialog", but that doesn't stop most people from satisfying their IDOL-wannabe-souls from publishing their personal dialogs without thinking twice about spamming everyone else who is following them. Direct messages exists, even within Twitter, if you are not happy with other instant messaging tools or Skype.

So what can be done about Twitter?

Probably nothing since the current behavior is so ingrown in people's minds, it will be impossible to change. But here are a few ideas:

A new better introductory question. Instead of "What's happening?" maybe:

What would you like to share with the world?

Think TED! What's an idea worth spreading? What would you like to share with the world?

It implies that it should be interesting to at least someone else, other than yourself.

It doesn't have to be right now. It is even preferred that it is something that you have been thinking about for a while.

If it is a conversation with someone else, please make it a conversation with someone else, not a public display of your stupidity (or intelligence, if you prefer that)! Use Direct Messages or IM-tools.

If the tweet cannot be said in 140 characters, you have failed. Twitter is a micro blog and if you are not able to say what you want in 140 characters, please write it up in a normal blog and tweet a link it. Sending five consecutive messages on the same topic only shows that you have failed to condense your message down to it's essentials. If it cannot be said in 140 characters, don't tweet it, blog it!

I am aware that not everyone thinks that Twitter sucks and that I am not using it properly. I should not look at old tweets, etc., etc., but I want to use it like this.

Filters

I am therefore working on a filter for filtering out all the crap. The filter goes under the obvious name, no-crap, and it currently contains 4 filters:

  • A Bayesian filter is like a personal spam filter and allows you to classify certain tweets as crap or not.
  • A stop-word filter is a filter, that does not allow tweets with specified words, such as Viagra, to get through.
  • A max-per-time filter stops the tweeters that tweet tons of interesting things, but do it at the expense of others. You can, for example, set this filter to max five tweets per day.
  • A duplicate-per-time filter stops the re-tweet overflow that can happen if something interesting comes a long. It compares the tweet and does not resend tweets higher than a given similarity.

This is currently a hobby project, so it does not get much attention. I invite anybody to steal my ideas, and to merge them into the current Twitter clients.

Sunday, November 29, 2009

Working at Jayway

This morning I woke up singing, like I do most mornings. :D There are so many things ahead of me and most of them I like to do. One of those things is going to work. I worked at Jayway, for five years, three years ago, and I recently came back.

The reason I left was that I wanted to work with one product and one team. I wanted to do everything right, I wanted to use pair-programming, domain-driven design and test-driven development. I had many plans. It didn't turn out that way, the people on the team I worked with did not want to use pair-programming, DDD or TDD! :(

After a few years I gave up and came back to Jayway and I love it. The company has grown quite a bit, while I was away, and that is a good thing. Three years ago I probably thought that it was a bad thing. It isn't! Three years ago we had to come into a company as resource consultants, but now we, many times, come in as a team or get to do the project in-house. This is a really good thing. Getting to work with other Jayway people is a real Joy. They are smart, motivated and pragmatic. If I leave the project for a week, someone steps into my role and, everything works out fine. People and interactions over processes and tools is very, very true!

There are a many reasons why I think it is so nice to work at Jayway.

Natural authority is a pattern from Adrenaline Junkies and Template Zombies that states:

The meaning of an authority is a person who knows a great deal about something. Another meaning, in authority, is a person who is in charge. If someone who is an authority also is in authority, this is a natural authority.

The person who knows best, gets to make the decisions. This is the way it is at Jayway. You are not assigned to a project, you are asked if you want to work on the project and, it is OK to say no.

Management. My wife recently told me about a danish entrepreneur, Lars Kolind. He is usually called in when a company is not doing as well as it should. He talked about something that he called Kolindkuren (the Kolind treatment). What he does in this treatment is that he turns things upside-down. And one specific thing he did was that instead of asking managers who they wanted as employees, he asked the employees who they wanted to have as managers. It turned out that no-one wanted many of the managers.

When I think about this and how this would work out if we did the same thing at Jayway, I don't think that anything would change. I am happy with my managers, I don't see them as managers, I see them as collegues who work to allow me to do the job I want to do. If I got to choose who I wanted to be my boss, I would choose exactly the people we have right now. And, I think we all feel the same way. An example of this came a few years ago.

Thomas, the president of Jayway was fired by the board. What happened then was amazing, one week after Thomas was fired, 90 percent of the employees had resigned. If Thomas can't work for you, then we wont work for you, was the clear message that was sent. And it had effect, Thomas is back, the board is gone, and we are all happy.

Competence is the driving factor of everyone at Jayway. We all have different interests, but the common denominator is that everyone loves programming and want to get better at it. Take a look at this weeks competence workshops, and remember that they are all voluntary!

Competence Calendar

Openness is very important to me. If I know why a decision has been made, I can understand why it was taken even though I may not agree with it. At Jayway all the managers write a short daily mail about what they are doing during the day. Every week Thomas updates the wiki with what is going on currently and what is planned for the future. Everything that does not have to be secret is open and available. If you want to find it, it is on the wiki.

If a doctor wants to chop of my leg I would be happier with the decision if I knew that he wants to do this because I have an incurable tumor in the leg, instead of him wanting to practice his amputation skills.

So, that is how it is to work at Jayway (at least in my mind). If you feel that competence and humbleness is more important than fancy titles, come and join us.

Tuesday, November 24, 2009

Under the Hood of git clone

When you clone a git repository, everything is automatically setup to allow you to fetch, pull, push to and from the remote repository, origin. But what is really going on? git remote is configured with a few lines of configuration in the config file inside the .git/ directory.

Here’s how it works:

Create a new repository, called base, add a file to it, then commit.
$ mkdir base;cd base;git init
Initialized empty Git repository in /Users/andersjanmyr/tmp/repos/base/.git/
$ echo foo > bar.txt
$ git add .
$ git commit -m initial
[master (root-commit) 548d762] initial
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 bar.txt
Clone this repository, called klon.
$ cd ..
$ git clone base klon
Initialized empty Git repository in /Users/andersjanmyr/tmp/repos/klon/.git/
Initialize a new repository, called kopy.
$ mkdir kopy;cd kopy;git init
Initialized empty Git repository in /Users/andersjanmyr/tmp/repos/kopy/.git/
The difference in configuration between the klon and the kopy.
$ diff klon/.git/config kopy/.git/config
7,12d6
< [remote "origin"]
<       fetch = +refs/heads/*:refs/remotes/origin/*
<       url = /Users/andersjanmyr/tmp/repos/base
< [branch "master"]
<       remote = origin
<       merge = refs/heads/master

To set up the newly created repository to work the same way the clone does, all I have to do is to edit this file to make it look the same. This is not what git does, so lets do it the git way.

Fixing the remote configuration.
$ cd kopy
$ git remote add origin /Users/andersjanmyr/tmp/repos/base
This adds the [remote "origin"] entry to the config file.
[remote "origin"]
        url = /Users/andersjanmyr/tmp/repos/base
        fetch = +refs/heads/*:refs/remotes/origin/*
Fetching from the origin adds the remote heads to .git/.
$ git fetch
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /Users/andersjanmyr/tmp/repos/base
 * [new branch]      master     -> origin/master
$ find .git/refs
.git/refs/
.git/refs/heads
.git/refs/remotes
.git/refs/remotes/origin
.git/refs/remotes/origin/master
.git/refs/tags

Now I can check out the origin/master, but if I do it the normal way, the configuration will not be set up correctly to allow me to pull and push the way i can with the clone.

Checkout the master version with tracking information.
# DON'T DO THIS, It does not add the tracking information to the config file.
$ git checkout -b master origin/master

# This add the tracking information to the config file.
$ git checkout --track -b master origin/master
Branch master set up to track remote branch master from origin.
Already on 'master'
The following information is added to .git/config when --track is used.
[branch "master"]
        remote = origin
        merge = refs/heads/master

That’s it! Now the .git/config file looks the same as if I had done a normal clone, but lets continue. What do the entries in the config file mean.

Definition of the remote.
[remote "origin"]
        url = /Users/andersjanmyr/tmp/repos/base
        fetch = +refs/heads/*:refs/remotes/origin/*
Definition of the remote as git config commands.
$ git config remote.origin.url /Users/andersjanmyr/tmp/repos/base
$ git config remote.fetch = +refs/heads/*:refs/remotes/origin/*

The first part is just declaring the alias origin for the remote url (or local in this case :).

The second part of the definition is more interesting. It sets up the refspec that will be used if you don’t provide anything on the command line. As we usually don’t provide a full refspec, most people don’t know what it is, this is extremely useful. In case you don’t know, the remote commands of git, push, pull, and fetch take a refspec as their last parameter. It is just that we usually just refer to a small part of it.

Usage of the remote git commands.
git pull <options> <repository> <refspec>...
git fetch <options> <repository> <refspec>...
git push <options> <repository> <refspec>...

The format of a refspec parameter is an optional plus +, followed by the source ref src, followed by a colon :, followed by the destination ref dest.

It defines what dest object should be updated by the src object.

Example definition of refspec.
# The local
# +<src>:<dest>
+refs/heads/spike:refs/remotes/origin/master

In our day-to-day usage of git, we usually don’t use the full syntax of the refspec. Instead we just refer to simple names. Like this.

Day-to-day usage of refspecs.
# Push the local branch to the remote branch with the same name
$ git push origin
# Pull the master into the local master.
$ git pull origin master
# Fetch the master of the origin and put the result in the remote experimental
$ git fetch origin master:refs/remotes/origin/experimental

The above really means:

Definition of the branch, expanded
# Push the local branch to the remote branch with the same name
$ git push refs/heads/*:refs/remotes/origin/*
# Pull the master into the local master.
$ git pull origin refs/heads/master:refs/remotes/origin/master
# Fetch the master of the origin and put the result in the remote experimental
$ git fetch origin refs/heads/master:refs/remotes/origin/experimental

From the above syntax, it is also possible to decrypt the obscure syntax used when deleting a remote branch. Deleting is the same as pushing to a remote branch without giving a local branch.

Delete a remote branch.
# Delete the remote branch serverfix
git push origin :serverfix

Now, we are down to the last part of the configuration, the branch definition.

Definition of the branch
[branch "master"]
        remote = origin
        merge = refs/heads/master

The first part branch.master.remote, tells git to use origin as the default remote, if none is given for this local branch.

The second part tells git which remote branch to use when merging. This also affects pull and fetch. Depending on your settings of push.default, it will also affect push.

Hopefully this has clarified some of the intricacies of git remoting. Just remember that if you make a mistake, you can always fire up an editor and edit the config file directly.

I’ll finish up with some more commands that can be used to get information about the remote.

Additional remote commands, to explore a remote.
# Show all remote branches
$ git branch -r
  origin/cucumber
  origin/customercare-0.6.x
  origin/master

# Show all remotes verbosely
$ git remote -v
origin  /Users/andersjanmyr/tmp/repos/base (fetch)
origin  /Users/andersjanmyr/tmp/repos/base (push)

# Show info about the remote
$ git remote show origin
* remote origin
  Fetch URL: /Users/andersjanmyr/tmp/repos/base
  Push  URL: /Users/andersjanmyr/tmp/repos/base
  HEAD branch: master
  Remote branches:
    experimental stale (use 'git remote prune' to remove)
    master       tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

# List the remote heads of the origin
$ git ls-remote --heads origin
548d7624f5385d36314e8ab61e61e8872c0bfe90        refs/heads/master

That’s it for today.

Tuesday, November 10, 2009

Adrenaline Junkies and Template Zombies

Since I had plenty of time to read on my flights back and forth to OOPSLA, I managed to read through a few books. One of them was Adrenaline Junkies and Template Zombies by Tom DeMarco et al. Being the sceptic that I am, my attitude when starting to read this book was: "Yeah, I know a lot of people has praised this book and I know that Tom DeMarco has written Peopleware, but what the hell do these bozos know anyway!" ;)

I figured that the six of them could probably scrape together a few decent people patterns, but I am a bit fed up with the whole pattern template style, so my expectations were not as high as they should have been.

Anyway, the book is amazing, the pattern template is really lightweight, basically, a name, an image, a statement, and a story. And the stories, are good. The authors have a remarkable ability to observe human nature and also the ability to write about what they see.

Some Patterns

The book contains 86 patterns, most of them are negative since they are funnier, as one of the authors said on a podcast.

Dead Fish

A dead fish is a project, that every one knows is impossible to start out with, but nobody says anything since the culture in the company is that way. If you say something you may get responses like,

Prove it! Prove that it is not feasible that this project will succeed!

Or,

Are you a weenie or a layabout?

Projects like this are usually worked on until it is inevitable that they will be late, and then everybody acts surprised.

Nanny

A nanny is a project manager that is aware of the capabilities of her staff and nurtures them and lets them at their peek. The nanny is responsible for improving her staff and make responsible project citizen of them. A nanny enables workers to do their job.

Eye Contact

If your life depended on a project, would you want them working close together or in different corners of the world? Human communication goes way beyond words, and it is foolish to think that it is possible to work at full speed with people who don't know each other and live in different places.

Dashboards

A dashboard is a highly visible board, that enable the project members and others to get an instant view of the status of the project. It can be a web page or a board on the wall. What is significant with a dashboard is that it is updated as soon as anything important happens in the project. All project members care for the dashboard since that is the place where they can find out how they are doing. Dashboards contain just the right amount of data.

Film Critics

A film critic is a project member or someone related to the project who thinks that they can succeed even if the project is a failure. They may often have good points, but usually when it is too late to do something about it. It is no use to have a person like this on the team, since they are not really on the team if they don't go down with the ship.

Natural Authority

The word authority have several meanings. The meaning of an authority is a person who knows a great deal about something. Another meaning, in authority, is a person who is in charge. A person who is an authority and in authority is a natural authority. This is the healthy pattern.

The White Line

The white line is the line on a tennis court. The line is a clear signal if the ball is in or out. Occasional dispute may arise over a questionable judgment call, but the line is respected by everyone. Most projects don't have this line. Create a white line for your project so that you know what is inside the project scope and what is not.

Silence Gives Consent

If someone don't oppose an idea, it is, usually, taken as consent. Especially from people who come from different working areas, like management and programmers. Silent consent is not good for anyone, because nobody is sure what has been decided and what has not. A way to remedy this problem is to keep a list of commitments where it is written down who has promised who what. The Scrum sprint backlog is similar to such a list.

Time Removes Cards from Your Hand

The earlier a decision can be made, the better. If you know that a project will not make a deadline, the decision to change the scope should be made as early as possible, since that will allow the team to work on the most important features first. If a decision is delayed until it is too late, the decision is made implicitly by time.

Rhythm

Instead of being daunted by overwhelming tasks, projects with rhythm take small, regular steps thus establishing a regular beat that carries them toward their goal.

This journey of a thousand miles begins with a single step --Lao Tzu

False Quality Gates

False quality gates are quality checks that don't do anything to promote the quality of the project. It is a sign that more attention is concentrated on format, rather than content. It can be a glossary of terms with the wrong content or a word template where most of the sections are filled in with the words "This section must contain text to fulfill company guidelines".

Testing Before Testing

Testing before testing refers to the practice of thinking about how to test a feature at the same time you think about how to implement it. If it cannot be tested how can you know that it does what you say?

Cider House Rules

Cider house rules are rules written by someone unconnected to the project. Rules like this, that give no apparent value, are a burden to the project and therefore often ignored.

Nobody pays attention to them rules. Every year Olive writes them up and every year nobody pays any attention to them. -- John Irving, The Cider House Rules

Talk Then Write

The team makes decisions during conversation, and then immediately communicates the decisions in writing. This is a really important pattern that it is easy to forget!. A common place where this kind of decisions are written down is very helpful.

Practicing the End Game

A team that does not release often and regularly will often take a long time to make a release. The act of releasing a product should be practiced often so that is becomes a natural part of the project.

Data Quality

Data quality often sucks! A common solution is often to attack the problem with technology instead of putting in the manpower that is actually needed to improve the quality of the data. Company web-sites are the prime example of this. They are often full of completely useless information.

Undivided Attention

Complex work is hard and it requires undivided attention to be performed properly. Splitting people's attention over multiple project will severely hinder their performance.

By doing two things at once, you've cut your IQ in half, and believe me, those 40 points can really make a difference. -- Dale Dauden, The New York Times

Orphaned Deliverables

Orphaned deliverables are deliverables that no-one values enough to pay for. Always make sure that there is a sponsor for every artifact that you are developing.

Hidden Beauty

Hidden beauty inside a program, that little extra thing, that may seem unnecessary, is what shows that the creator cares about his work. It is not unnecessary! This caring is what separates a quality product from garbage.

I Don't Know

If you are afraid of saying the words, "I don't know!", you are probably working in an organization where saying it means that you will be taken for a fool. In a healthy organization, "I don't know!", means that you don't know, but you will in a while, if it is important enough.

Loud and Clear

Having a clear goal, that everyone agrees to, is vital to a project. Clear goals allows you to focus the project activity if it starts to move away from its purpose. A PAM statement, that contains the Purpose, Advantage, and Measurements of a project is very helpful.

Conclusion

The patterns described above are just my short summaries, and I don't do them justice, but hopefully I have awoken your interest in this wonderful book.

It made my top-ten list and I recommend it to everyone from programmer to president. I like that the authors don't always provide a solution, but instead just describe the way they see it, it is up to you to figure out a solution to the problem yourself.

Saturday, November 07, 2009

The Craftsman Analogy

The analogy of software developers as craftsmen has become very popular. I don't know where it started, but the first book I read about it was the excellent book The Pragmatic Programmer by Andy Hunt and Dave Thomas. I really liked this analogy, it seemed right.

A few years later, Pete McBreen released the book Software Craftsmanship, where he articulates that software development should be more like craftsmanship. Pete writes eloquently about programming masters that should be paid ten times more than their apprentices because they are at least ten times more effective. The masters also have the responsibility to take on journeymen and apprentices to train in their particular flavor of software development. This also rang very true to me.

But, there is something fishy with this analogy. Something ain't right!

I have come to understand that the analogy refers to how it is believed that the craftsman "industry" worked ages ago, rather than how it is today. If you hire a carpenter today he may tell you that he will come "sometime next week". I have rarely been given a time that is more exact than a four hour span, to just meet up.

After the meeting has been scheduled, I have to be very lucky if my craftsman actually appears at the appointed time. Most of the time he will not show up at all!

If I happen to be lucky enough to get a craftsman to show up or to call and tell me that he can't make it, I usually make a note of this guy as being, a highly reliable craftsman, worth hiring again. He gets a golden star for just calling to tell me that he won't come.

When we finally meet up, the craftsman may do a terrific job and I will happily recommend him to anyone, but most likely we will talk and he will tell me that he doesn't have the time to do the job right now, but that he can come back tomorrow. If you let him go with that, he most likely will not come back tomorrow or the next day. He will come back when you call to remind him that he should have come back. And even better, if you pay him in advance you will never see him again, ever!

So, if our goal is to get programmers to be viewed as craftsmen, we're already there. Just change the statement those f***ing carpenters never do what we expect! to those f***ing programmers never do what we expect!

Maybe the whole idea of programmers as craftsmen is just:

It was better in the old days.

It wasn't, it is better now!

I have learned one thing through all my years of programming:

The more I learn, the more I learn how little I know. --Socrates

I'm not a software craftsman, I'm a humble programmer, a good one, and proud of it.