Maven 2.1.0 is out!

After much anticipation, Maven 2.1.0 has been released. My personal favorite new feature is the parallel downloads of artifacts. This alone should significantly speed up builds on CI servers that refresh the repo on each build.

Go get yours today.

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

Leaving India: My Sister’s Book!

My sister’s book is now available on amazon. Go check it out!

Getting OCMock to work

I started using OCMock yesterday, and was quickly hit by a problem when trying to stub out return values.

My test method was (sorry for the lack of highlighting - the plugin i’m using doesn’t support Objective-C)

- (void)testReturnsStubbedReturnValue
{
	id mock = [OCMockObject mockForClass:[NSString class]];
	[[[mock stub] andReturn:@"megamock"] lowercaseString];
	id returnValue = [mock lowercaseString];

	STAssertEqualObjects(@"megamock", returnValue, @"Should have returned stubbed value.");
}

However, when running it, I would get the error:

  warning no '-stub' method found
  warning no '-andReturn' method found

After scrolling through all the OCMock test code, I finally was able to get it work by adding:

  #import <OCMock/OCMock.h>

That’s where the methods are defined, but not being an Obj-C guru, I don’t fully understand how the code knows it’s actually using the OCMock class, etc.

Anyway, it appears that the minimal code needed to get an OCMock test running is (i wish this was on their web site!):

In OCMockSampleTest2.h:

#import <SenTestingKit/SenTestingKit.h>

@interface OCMockSampleTest2 : SenTestCase {
}

@end

In OCMockSampleTest2.m:

#import "OCMockSampleTest2.h"
#import <OCMock/OCMock.h>
#import <OCMock/OCMConstraint.h>

@implementation OCMockSampleTest2

- (void)testReturnsStubbedReturnValue
{
	id mock = [OCMockObject mockForClass:[NSString class]];
	[[[mock stub] andReturn:@"megamock"] lowercaseString];
	id returnValue = [mock lowercaseString];

	STAssertEqualObjects(@"megamock", returnValue, @"Should have returned stubbed value.");
}

@end

I hope this helps someone!

Why I Use Maven

I was asked recently why I like Maven so much. Here’s why:

  • The most basic project structure will compile code, run all your unit tests, and build a jar file:
    <project>
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.chikli.testprojecct</groupId>
      <artifactId>testproject</artifactId>
      <version>1</version>
    </project>
  • Due to the standardization, and logical defaults/conventions, I can open up any project that uses Maven for it’s build system and immediately understand the build process and the generated artifacts. This is in stark contrast to ant buildfiles which are custom from project to project.
  • Since all needed artifacts (jars) are versioned and live in a Maven Repository, I don’t have to include the actual jar files for third party libraries within my project structure.
  • I can run a single command and immediately see if any of the libraries that my project uses has released any updates (i.e. new versions of spring, hibernate, commons-*, etc):
    • mvn versions:display-dependency-updates
  • I can change the version of a library that my project uses simply by typing in the version I want.
  • Documentation - this has traditionally been horrible for Maven, but Sonatype has recently created an excellent free online book that covers all you need to know about using Maven.

I’m pretty sure there’s more I like about Maven, but these are the ones that came to me right away.

A Successful Attempt at Mangling Ruby

I’m working on the Ruby Koans by Edgecase which has been a really nice way to introduce myself (again) to Ruby. It’s the right mix of hand-holding and “solve-it-yourself” problems.

I just finished the about_proxy_object_project.rb Koan, and while it works, I fear that I’ve fairly well mangled Ruby, and there are probably infinitely more elegant ways to do this. My code looks like Java transcribed into Ruby.

Anyway, here is the code. If you have some spare time, take a look and see what I could have done better. I wrote the Proxy class, the rest was supplied.

# Project: Create a Proxy Class
#
# In this assignment, create a proxy class (one is started for you
# below).  You should be able to initialize the proxy object with any
# object.  Any messages sent to the proxy object should be forwarded
# to the target object.  As each message is sent, the proxy should
# record the name of the method send.
#
# The proxy class is started for you.  You will need to add a method
# missing handler and any other supporting methods.  The specification
# of the Proxy class is given in the AboutProxyObjectProject koan.

class Proxy

  class MessageLog
    attr_accessor :message_name
    attr_accessor :count

    def initialize(message_name)
      @message_name = message_name
      @count = 1
    end

    def increment_count
      @count = @count + 1
    end

  end

  def initialize(target_object)
    @object = target_object
    @messages = []
  end

  def method_missing(method_name, *args, &block)
    if @object.respond_to?(method_name)
      increment_message_count(method_name)
      @object.send(method_name, *args, &block)
    else
      super(method_name, *args, &block)
    end
  end

  def increment_message_count(message_name)
      message_log = called?(message_name)
      if message_log.nil?
        @messages < < MessageLog.new(message_name)
      else
        message_log.increment_count
      end
  end

  def messages
    @messages.collect { |message_log| message_log.message_name }
  end

  def called?(command)

    matched_message_log = nil

    @messages.each do |message_log|
      if message_log.message_name == command
        matched_message_log = message_log
      end
    end

    matched_message_log
  end

  def number_of_times_called(command)
    message_log = called?(command)

    message_log.nil? ? 0 : message_log.count
  end

end

# The proxy object should pass the following Koan:
#
class AboutProxyObjectProject < EdgeCase::Koan
  def test_proxy_method_returns_wrapped_object
    # NOTE: The Television class is defined below
    tv = Proxy.new(Television.new)

    assert tv.instance_of?(Proxy)
  end

  def test_tv_methods_still_perform_their_function
    tv = Proxy.new(Television.new)

    tv.channel = 10
    tv.power

    assert_equal 10, tv.channel
    assert tv.on?
  end

  def test_proxy_records_messages_sent_to_tv
    tv = Proxy.new(Television.new)

    tv.power
    tv.channel = 10

    assert_equal [:power, :channel=], tv.messages
  end

  def test_proxy_handles_invalid_messages
    tv = Proxy.new(Television.new)

    assert_raise(NoMethodError) do
      tv.no_such_method
    end
  end

  def test_proxy_reports_methods_have_been_called
    tv = Proxy.new(Television.new)

    tv.power
    tv.power

    assert tv.called?(:power)
    assert ! tv.called?(:channel)
  end

  def test_proxy_counts_method_calls
    tv = Proxy.new(Television.new)

    tv.power
    tv.channel = 48
    tv.power

    assert_equal 2, tv.number_of_times_called(:power)
    assert_equal 1, tv.number_of_times_called(:channel=)
    assert_equal 0, tv.number_of_times_called(:on?)
  end

  def test_proxy_can_record_more_than_just_tv_objects
    proxy = Proxy.new("Code Mash 2009")

    proxy.upcase!
    result = proxy.split

    assert_equal ["CODE", "MASH", "2009"], result
    assert_equal [:upcase!, :split], proxy.messages
  end
end

# ====================================================================
# The following code is to support the testing of the Proxy class.  No
# changes should be necessary to anything below this comment.

# Example class using in the proxy testing above.
class Television
  attr_accessor :channel

  def power
    if @power == :on
      @power = :off
    else
      @power = :on
    end
  end

  def on?
    @power == :on
  end
end

# Tests for the Television class.  All of theses tests should pass.
class TelevisionTest < EdgeCase::Koan
  def test_it_turns_on
    tv = Television.new

    tv.power
    assert tv.on?
  end

  def test_it_also_turns_off
    tv = Television.new

    tv.power
    tv.power

    assert ! tv.on?
  end

  def test_edge_case_on_off
    tv = Television.new

    tv.power
    tv.power
    tv.power

    assert tv.on?

    tv.power

    assert ! tv.on?
  end

  def test_can_set_the_channel
    tv = Television.new

    tv.channel = 11
    assert_equal 11, tv.channel
  end
end

SLIM on FitNesse

Uncle Bob has posted a nice video covering basic usage of the new SLIM framework within FitNesse. It appears to streamline some (but not all) of the annoyances of the current FitNesse processing.

I have yet to try it, but it certainly looks promising, especially for people writing tests for multiple platforms.

CodeMash Presentations

The sessions for the upcoming CodeMash conference were announced on the email list last night. It looks like a great list of sessions that will be posted shortly on the official site.

Unfortunately, the sessions that I submitted were not selected. There’s always next year, but in the spirit of optimism there are a couple nice side effects of this:

  1. More free time since I don’t have to prepare presentations.
  2. More time at the conference to play Rock Band. Please tell me someone is bringing it. =)

Anyway, for those who are interested, here are the abstracts that I submitted:

Enterprise Build & Deployment Ecosystems

One of the most forgotten/ignored aspects of software development is the build/deployment process. Teams tend not to give it much thought until a couple weeks before actual deployment time, and then ad hoc solutions are rushed into place that sometimes create more problems than they solve.

Build/Deploy nirvana consists of:

  1. Low setup-cost for new team members
  2. Code AND Database version control
  3. Easily repeatable builds
  4. Automated release versioning
  5. Pushbutton deployments to all environments.

This session will present a set of Best Practices(TM) needed to make this vision a reality, as well as one possible implementation using Maven (Build), Hudson (Continuous Integration), and LiquiBase (Database Change Management).

ICEfaces: Ajax Interfaces with JEE Power

Tired of fighting with Javascript to build an AJAX-enabled application? Sick of developing UIs that are not easily integrated into your JUnit test harness?

ICEfaces is a fully Ajax enabled implementation of the JSF (Java Server Faces) specification. Build all your components in (testable) Java, write your pages with ICEfaces/JSF tags, and ICEfaces magically generates the cross-browser Ajax interface elements with dynamic updates.  You can leverage the full enterprise power of the JEE stack with ease. It’s open source too!

This session will present the fundamentals of ICEfaces, it’s benefits and drawbacks, as well as how you can start using it in your application.

Iterations are Bad for Your Health

Well, not really, but iterations are not as important some of the Agile community makes them out to be, in the way that they are typically thought of.

Short iterations. Long iterations. Who gives a rip? The important thing is that you are regularly tracking your team’s velocity. Take this Big Visible Velocity Chart from my current project:

Ouch! That Velocity Hurts!

Ouch! That Velocity Hurts!

We track velocity weekly (using Ideal Days), only counting up the velocity for stories that are completed before Monday morning. As you can see, we seem to have developed a fairly regular cadence of slow week/fast week/slow week/fast week… So what’s going on here? Do we bring a keg into the team room every other week? Are we really bad at estimating?

Actually, the cause of this sawtooth motion is simply that we tend to not be *quite* done with things in a given week, so a lot of the stories get counted in the following week’s tally. For example, in Week 7, we had two 4 iDay stories and one 2 iDay story allocated. The 2 iDay story was completed by the end of the week, but the the 4 iDay stories didn’t get finished until the following Monday afternoon. Therefore, we counted 2 iDays for week 7, and the remaining 8 were lumped into the week 8 metric.

Now, we could get into a big discussion about how our stories are too big, or that our iterations are too short, but in reality it doesn’t really matter. What matters is that from the data we’ve collected, we can come up with a fairly accurate measure of our teams velocity. (We had a string pulled across the chart that we adjusted each week to indicate the trend line, but the tape wasn’t strong enough to hold it up). We can use that velocity to estimate our team’s capacity and deliverable dates, and have done just that on this project.

By the way, in case you hadn’t noticed, this chart is *proof* that our team’s velocity is “off the charts” :-)

What do you think? Are iterations overrated?

Michigan Agile Enthusiasts Chair

Hello everyone –

I’m running for the chair of the Michigan Agile Enthusiasts Group — If you get a chance, join up and vote for me!

Thanks!

CodeMash 2009

The CodeMash 2009 Conference in beautiful Sandusky, Ohio was just announced.

Last year was a blast. In addition to the copious amounts of Rock Band that was played, and waterslides that were slid on, I presented a session on Continuous Integration. This year, I plan to propose a session around deployment and artifact management. Sounds exciting, right?

See you there!