Oct 30 2009

Reviewing “97 Things Every Project Manager Should Know”

Category: agile,reviewgiordano scalzo @ 12:51 pm

97 things every project manager should know
O’Reilly continues its serie “97 things” with this “97 Things Every Project Manager Should Know“.
I’d like to define this kind of books as post-modern book: their contents are released under Creative Commons, every piece last just two pages and they are written by a large group of authors; they are a sort of blog on paper.

I started to read with great expectatives: most of authors are well known in Project Management world, and the format is very attractive.
Neverthless I found it too high level and, in some part, too superficial for my taste: I cought myself thinking “… and so?” too often.

In conclusion, I suggest this books only for novice project managers, otherwise a book as “Manage It!” by Johanna Rothman is more suitable.

Technorati Tags: , ,

Tags: , ,


Oct 26 2009

Birthday Greetings Kata in Ruby

Category: agile,ruby,tutorialgiordano scalzo @ 9:30 pm

Lately the pratice of Kata seems spreading out very quickly, thanks to work of well known Software Craftsmen as Corey Haynes or the Clean Code evangelist Uncle Bob.

It all started waiting for a kid’s karate lesson, and now it’s a well know practice to become a better developer.

Basicly a code kata is a small problem to be resolved without any pressure and requests, but to play with different techniques or programming language.

Another interesting point of view considers a code kata as a training for muscles of memory, focusing on repetitions, memorizations of decisions and keyboard shortcuts; the point is: if I get trained to do design decisions at subconscious level, when I’ll met similar problems I’ll be very productive, doing the right decision without any logical think.
Amazing, isn’t it?

The main argument of last Milan Xpug meeting was the Birthday Greetings Kata, a workshop Matteo Vaccari will submit to next Xp Days Benelux 2009.
Unfortunately I couldn’t be present, but I implemented the kata on my own, using Ruby instead of Java.

I enjoyed it very much, and I start thinking to try it still a couple of times and then screencasting it: I’m far behind this level, but review my actions can help me get better.

$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
require 'rumbster'
require 'message_observers'
require 'net/smtp'
require 'gserver'
require 'birthday_service'
require 'employee_repository'

describe "Greetings Service" do
	NON_STANDARD_PORT = 10015
	def send_message(to, message)
    		Net::SMTP.start('localhost', NON_STANDARD_PORT) do |smtp|
      			smtp.send_message message, 'your@mail.address', to
    		end
	end
	before :each do
	 	@rumbster =  Rumbster.new(NON_STANDARD_PORT)
   		@message_observer = MailMessageObserver.new
		@rumbster.add_observer @message_observer
		@rumbster.start

		@birthdayService = BirthdayService.new("localhost", NON_STANDARD_PORT);
	end
	after :each do
		@rumbster.stop
	end
	context "with a file with one person born today" do
		before :each do
			@birthdayService.send_greetings EmployeeRepository.new("employee_data.txt"), "2008/10/08"
		end

		it "should send one email" do
			@message_observer.messages.size.should == 1
		end

		it "should send correct message" do
			@message_observer.messages.first.subject.should == "Happy Birthday!"
			@message_observer.messages.first.body.chomp.should == "Happy Birthday, dear John!"
			@message_observer.messages.first.to.should == ["john.doe@foobar.com"]
		end
	end

end
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
require "employee_repository"

describe "EmployeeRepository" do
	it "should read Employees from a file" do
		repository = EmployeeRepository.new "employee_data.txt"
	end

	it "should have a well know size" do
		repository = EmployeeRepository.new "employee_data.txt"
		repository.size.should == 3
	end
	it "should return first employee" do
		repository = EmployeeRepository.new "employee_data.txt"
		expected_employee = Employee.new("Doe, John, 1982/10/08, john.doe@foobar.com")
		repository.first.should == expected_employee
	end
	it "should return employees born an a given date" do
		repository = EmployeeRepository.new "employee_data.txt"
		expected_employee = Employee.new("Doe, John, 1982/10/08, john.doe@foobar.com")
		repository.born_on('2008/10/08').first.should == expected_employee
	end
end
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
require "message"
require "employee"

describe "Message" do
	before :each do
		@message = Message.new Employee.new("Doe, John, 1982/10/08, john.doe@foobar.com")
	end

	it "should have employee's email as destination" do
		@message.to.should == "john.doe@foobar.com"
	end
	it "should construct a complete body" do
		@message.body.should == "To: john.doe@foobar.com\nSubject: Happy Birthday!\n\nHappy Birthday, dear John!"
	end
end
require "message"

class BirthdayService
	def initialize(host, port)
		@host = host
		@port = port
	end
	def send_greetings(employees, date)
		employees.born_on(date).each do |employee|
			send_message(Message.new employee)
		end
	end
	def send_message(message)
    		Net::SMTP.start(@host, @port) do |smtp|
      			smtp.send_message message.body, 'your@mail.address', message.to
    		end
	end
end
class Employee
	attr_reader :firstname
	attr_reader :lastname
	attr_reader :birthdate
	attr_reader :email
	def initialize(args)
		tokens = args.split(',').map { |e| e.strip }
		@firstname = tokens[1]
		@lastname = tokens[0]
		@birthdate = tokens[2]
		@email = tokens[3]
	end

	def ==(other)
		other.instance_of?(self.class) &&
			@firstname == other.firstname &&
			@lastname == other.lastname &&
			@birthdate == other.birthdate &&
			@email == other.email
	end
end
require 'employee'

class String
	def same_day?(other)
		date1 = split('/')
		date2 = other.split('/')
		date1[1] == date2[1] && date1[2] == date2[2]
	end
end

class EmployeeRepository
	private
	def skip_header
		@employees.shift
	end

	public
	def initialize(employees_filename)
		@employees = []
		File.open(employees_filename).each_line do |line|
			@employees << Employee.new(line)
		end
		skip_header
	end

	def size
		@employees.size
	end

	def first
		@employees.first
	end

	def born_on(current_date)
		@employees.find_all { |e| e.birthdate.same_day?(current_date) }
	end
end
class Message
	def initialize(employee)
		@employee = employee
	end
	def to
		@employee.email
	end
	def body
		["To: #{to}",
		"Subject: Happy Birthday!",
		"",
		"Happy Birthday, dear #{@employee.firstname}!"].join("\n")
	end
end

Interesting I wrote more specs code than production code.

I do like I didn't used any IF, but I don't like to open String to model date and the use of split to tokenize things: I'll focus on thant in next attempt!

Technorati Tags: ,

Tags: ,


Oct 23 2009

Caps Lock day

Category: megiordano scalzo @ 10:20 am

A friend of mine pointed out this site celebrating the Caps Lock Day.

It happens I really don’t like Caps lock: often pressing tab I enable the caps lock, screwing up my writings, passwords, etc.

In good old days when I was a full time programmer on Unix, I used to remove that key; in the name of those glorious days this is my keyboard today:

capslock

If you prefere something less radical, CapsLockBeGone that produces the same effect.

Technorati Tags:

Tags:


Oct 21 2009

No more excuses: junit testing log messages

Category: java,tutorialgiordano scalzo @ 7:46 pm

Althought I’m a straight adept of Tdd, sometime I can’t resist the temptation to write some production code without a test, above all if I have to implement some cross cutting behaviours, as could be logging .

In project I worked on lately, a request was to manage some bad situations logging something at error level and go process next item; the temptation to implement it and check running the program was very appeliling, but my green wrist band and RailsConf 09 keynote by Uncle Bob I watched recentely, helped me resist.
So I started searching, tried somenthing, and, finally, I came up with a neat solution.

Given this simple object

package biz.scalzo.prod;

import org.apache.log4j.Logger;

public class LoggingObject {
	private static Logger log = Logger.getLogger(LoggingObject.class);

	public void starts() {
		log.info("I'm starting");
	}
}

we want to test if it writes log.
To achieve this, we can use a simple custom appender, that records all messages in a list:

package biz.scalzo.test;

import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;

public class RecordingAppender extends AppenderSkeleton {
	private static List<String> messages = new ArrayList<String>();
	private static RecordingAppender appender = new RecordingAppender();

	private RecordingAppender() {
		super();
	}

	public static RecordingAppender appender(PatternLayout patternLayout) {
		appender.setLayout(patternLayout);
		appender.clear();
		return appender;
	}

	protected void append(LoggingEvent event) {
		messages.add(layout.format(event));
	}

	public void close() {
	}

	public boolean requiresLayout() {
		return true;
	}

	public static String[] messages() {
		return (String[]) messages.toArray(new String[messages.size()]);
	}

	private void clear() {
		messages.clear();
	}
}

With that, writing our test is a piece of cake:

package biz.scalzo.test;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

import biz.scalzo.prod.LoggingObject;

public class ALoggingObject {

	private LoggingObject loggingObj;

	@Before
	public void setUp() {
		loggingObj = new LoggingObject();
		configureLog();
	}

	private boolean logContains(String expected) {
		String actual[] = RecordingAppender.messages();
		for (String log : actual) {
			if (log.contains(expected))
				return true;
		}
		return false;
	}

	private void configureLog() {
		Logger rootLogger = Logger.getRootLogger();
		rootLogger.removeAllAppenders();
		rootLogger.setLevel(Level.INFO);
		rootLogger.addAppender(new ConsoleAppender(new PatternLayout(
				"%d [%t] %-5p %c{1} - %m%n")));
		rootLogger.addAppender(RecordingAppender.appender(new PatternLayout(
				"%-5p - %m%n")));
	}

	@Test
	public void shouldLogWhenStarts() {
		loggingObj.starts();
		assertTrue(logContains("I'm starting"));
	}

}

Neat, simple and clear: no more excuses to not test logging!

Technorati Tags: , ,

Tags: , ,


Oct 20 2009

My solution to RPCFN 2

Category: bdd,rubygiordano scalzo @ 2:22 pm

The solutions for RPCFN 2 are now under judgement, so it’s the time to show my effort.

The problem was easy, but a little tricky: given a list of time of day, the program should find the average time.
The tricky part was to manage “am” and “pm” times, mapping them in date format: given “11:59am” and “12:00am”, then average time should be midnight.

My solution is based on the principle than if the range between “am” and “pm” times is under half a day, they are in the same day, otherwise a day leap occurs; this approach worked well, althought it needed a little bit of explanation in code, as noted by Chris himself ;-) .

These are my spec:

$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
require 'average_time_of_day'

describe 'average_time_of_day' do
	context 'for "06:00pm" and "07:00pm"' do
		it 'should be "06:30pm"' do
			avg = average_time_of_day(["06:00pm", "07:00pm"])
			avg.should == "06:30pm"
		end
	end
	context 'for "06:00pm", "07:00pm" and "08:00pm' do
		it 'should be "07:00pm"' do
			avg = average_time_of_day(["06:00pm", "07:00pm", "08:00pm"])
			avg.should == "07:00pm"
		end
	end
	context 'for "06:41am", "06:51am" and "07:01am' do
		it 'should be "06:51am"' do
			avg = average_time_of_day(["06:41am", "06:51am", "07:01am"])
			avg.should == "06:51am"
		end
	end

	context 'for "23:59pm" and "12:01am' do
		it 'should be "12:00am"' do
			avg = average_time_of_day(["23:59pm", "00:01am"])
			avg.should == "12:00am"
		end
	end

	context 'for "11:51pm", "11:56pm", "12:01am", "12:06am" and  "12:11am"' do
		it 'should be "12:01am"' do
			avg = average_time_of_day(["11:51pm", "11:56pm", "12:01am", "12:06am", "12:11am"])
			avg.should == "12:01am"
		end
	end

	context 'for "11:15pm", "12:03am", "11:30pm", "11:23pm", "11:48pm"' do
		it 'should be "11:35pm"' do
			avg = average_time_of_day(["11:15pm", "12:03am", "11:30pm", "11:23pm", "11:48pm"])
			avg.should == "11:35pm"
		end
	end

	context 'for "05:15am", "06:03am", "05:30am", "05:23am", "05:48am"' do
		it 'should be "05:35am"' do
			avg = average_time_of_day(["05:15am", "06:03am", "05:30am", "05:23am", "05:48am"])
			avg.should == "05:35am"
		end
	end

	context 'for "11:15am", "12:03pm", "11:30am", "11:23am", "11:48am"' do
		it 'should be "11:35am"' do
			avg = average_time_of_day(["11:15am", "12:03pm", "11:30am", "11:23am", "11:48am"])
			avg.should == "11:35am"
		end
	end

	context 'for "6:00pm" and "6:00am' do
		it 'should be "12:00am"' do
			avg = average_time_of_day(["6:00pm", "6:00am"])
			avg.should == "12:00am"
		end
	end

	context 'for "12:01am", "11:51pm", "11:56pm",  "12:06am" and  "12:11am"' do
		it 'should be "12:01am"' do
			avg = average_time_of_day(["12:01am", "11:51pm", "11:56pm", "12:06am", "12:11am"])
			avg.should == "12:01am"
		end
	end

end

and this are my code:

require 'time'

private
class Array
	def to_sec
		map {|t|t.to_f}
	end

	def avg
		(size > 0) ? to_sec.inject(0.0){|sum,el| sum + el}/size : 0

	end
end

class Time
	def am?
		hour < 12
	end

	def pm?
		not am?
	end

	def to_s
		strftime("%I:%M%p").downcase
	end

end

DAY_IN_SEC = 24*60*60

def adjust_order_for(times)
	to_adjust?(times) ? adjusted(times) : times
end

def to_adjust?(times)
	avg_am = times.select { |t| t.am? }.avg
	avg_pm = times.select { |t| t.pm? }.avg
	avg_pm - avg_am  >= DAY_IN_SEC/2
end

def adjusted(times)
	times.map { |t|(t.am? ? t+DAY_IN_SEC : t) }
end

public
def average_time_of_day(times)
	times = adjust_order_for(times.map { |t| Time.parse(t) })

	Time.at(times.avg).to_s
end

Next Quiz is scheduled for 1st Nov. 2009, and will be provided by Gautam Rege.

Technorati Tags: ,

Tags: ,


Oct 15 2009

Gibbon: add story to RSpec

Category: bdd,rubygiordano scalzo @ 10:31 am

I really do like Rspec and so do Cucumber, but, often, I don’t like switch between them during my develompment.
Today I stumbled upon ‘Gibbon‘ a clever hack by Stephen Caudill, of tomatoi.st fame,
that add support for GIVEN/WHEN/THEN templates.

It simple needs to add this file into your spec/support directory:

module Spec::DSL::Main
  alias :Feature :describe
  def Story(description)
    @description_args.push("\n#{description}\n")
  end
end

module Spec::Example::ExampleGroupMethods
  def executes(scope=:all, &blk)
    before(scope, &blk)
  end

  def Scenario(description, &blk)
    describe("Scenario:  #{description}", &blk)
  end

  def Background(description, &blk)
    describe("Background #{description}", &blk)
  end

  def Given(description, &blk)
    describe("Given #{description}", &blk)
  end

  def When(description, &blk)
    describe("When #{description}", &blk)
  end

  def Then(description, &blk)
    example("Then #{description}", &blk)
  end

  def And(description, &blk)
    example("And #{description}", &blk)
  end

  def But(description, &blk)
    example("But #{description}", &blk)
  end
end

and it’ll be possible write specs like that:

  Feature "A Tomatoist does a pomodoro" do
    Story <<-eos
    In order to perform a focused unit of work
    As a Tomatoist
    I want to start a pomodoro
    eos

    Scenario "Starting a pomodoro" do
      When "I go to the home page" do
        executes { visit '/' }

        Then "I should be sent to a new session" do
          current_url.should =~ /\/\w{3,}/
        end

        And "I should see an unstarted timer" do
          response.should have_tag('#timer .countdown_row','00:00')
        end

        And "I should see a pomdoro button" do
          response.should have_tag('input[type=submit][value=?]','Pomdoro')
        end

        When "I click the pomodoro button" do
          executes do
            @session_url = current_url
            click_button 'Pomodoro'
          end

          Then "I should be on my session's page" do
            current_url.should == @session_url
          end

          And "my timers should have been initialized" do
            response.should have_tag('#timer .countdown_row','25:00')
          end

          And "my timer history should show the current pomdoro" do
            response.should have_tag('#history ul li', /Pomodoro/, 1)
          end

          And "the pomodoro button should be highlighted" do
            response.should have_tag('form.current input[type=submit][value=?]','Pomdoro')
          end
        end
      end
    end
  end
  

Neat hack, indeed!

I'll try it as soon as possible.

Technorati Tags: ,

Tags: ,


Oct 10 2009

Entering RPCFN #2

Category: rubygiordano scalzo @ 7:12 pm

Quite satisfied for my result in first quiz, I’m enjoying writing some code for the second Ruby Programming Contest For Newbie, “Average arrival time for a flight”.

Despite it looks more easy than the previous, it needs some tricks and exploiting some Ruby idioms to resolve it effectively.

I’ll comment my entry when the contest is over.

Thanks to Chris Strom and Satish Talim for this challenge!

Technorati Tags: ,

Tags: ,


Oct 05 2009

Software Craftsmanship Tags

Category: agilegiordano scalzo @ 11:56 am

On Software Craftsmanship mailing list, it was asked three words describing what is Software Craftsmanship movement: this is the result


Wordle: SCTAGS2009

Technorati Tags:

Tags:


Oct 05 2009

Ruby Programming Challenge For Newbies: a chance to improve Ruby knowledge

Category: rubygiordano scalzo @ 11:05 am

Some day ago, I stumbled upon on a post by Satish Talim in his useful Ruby Learning Blog, announcing a Ruby Quiz for Newbies:
what a wonderful opportunity to learn better Ruby and Rspec!

The first challenge was proposed by a Fabio Akita, a well know Ruby and Rails evangelist, and it’s about a script that add, or subtract, an amount of time from a subtitles file.

I discovered the challenge a bit late, so I’d to rush to complete it in time, but I’m quite satisfied with the result; I don’t like the IF in main method, and it’s lack a robust correctness checking of command line’s arguments: I’ll try to remove explicit conditions and clean more in next challenge.

I pushed my attempt to GitHub, http://github.com/gscalzo/ShiftSubtitle, so I can improved it, after seeing other partecipants’ entries.

I have to credit solution to check System.exit to Charles Feduke: Thanx Charles!
Next quiz is scheduled for 9th Oct. 2009 proposed by Chris Strom: I really looking forward to it!

Update
I have to buy a mac! ;-)

Technorati Tags: , ,

Tags: , ,


Oct 02 2009

My Green Wristband

Category: agilegiordano scalzo @ 2:17 pm

As every software craftsman should know, UncleBobMartin has prepared a wonderful green wristband to remember to produce Clean Code.

I’m on my way to become a better developer, and Clean Code wristband is a sign of my commit.
After a small donation, today I got mine:

Clean Code Green Wristband

Clean Code Green Wristband

I’ve to admit I don’t feel I deserve it: the current project I’m working on is a doomed legacy system and the tempations to write dirt code are very appealing , but wearing it should help me to resist.


Next Page »