3/13/2009

Careful, Java Programmers going to Ruby

Good evening everyone, I am a Java programmer.
It happened quickly, I didn't even notice.
One day I was merrily strncpy'ing and the next it was immutable.


We joke about languages of old while new shinny languages are paraded in front of us, but in the end they all teach us something and make us forget other things.

Today I came across the first serious change that the Java world thrust upon my weak mind. I am working a Ruby project, a great new shinny language which is lots of fun to learn and work with.

When working in Java I use the usual Agile development process; write your test, write some code and repeat. As I progress, my code, and indeed the API design, evolve into a nice usable, stable set of libraries.

Working in Java, with Eclipse, the simplest technique is to start by writing your test, reference a public method, press a key to create it and flush out the implementation. As you go, you will naturally refactor pieces of code into new methods to keep it simple.

Well, this is where things get a little too easy for Java developers in Eclipse. To refactor a block of code into a new method just select it, press a couple of keys and Eclipse creates the new method for you. A new private method in the same class.

Sounds good right? Well it is, except, that you have now learned to not thing about the scoping your your methods when you create them. Your first is always public or protected because your test is driving it and subsequent methods are private by default as created by the IDE. It's a beautiful system.

Now you switch to Ruby.

You write your test and implement your public method, you refactor with the cut/paste/rename/suffle and low and behold, because you have learned not to think about it, you have loads of public methods in your class.

The project I am working on takes it one step further and has tests for every method, examining all its nuances, mocking all its dependencies and going to town making the implementation as couple to the test as possible. It's easy to do, they are all public, what else is a programmer to do?

Unit testing philosophy does vary depending on who you talk to but my basic goal is to:

  • Test all public methods,

  • Test all protected methods,

  • If a private method is particularly complex make it protected and test it,

  • If I have loads of "untested" private methods I need to move some to new classes and make them public. I leave it to you to quantify "loads".

  • Trust your coverage tool to tell you the private code you never use and delete it.


So, starting tomorrow, I change my Ruby development process and consider all new methods private unless part of a test driven process. This will do lots of things to improve the final product:

  1. Simplify the test/code dependencies making the tests less brittle.

  2. Prevent call sequence bugs where you have to call one method before another or it all falls over. Too many publics will do that you know.

  3. Make the calling conventions exposed by the class easier to grok by new programmers reading the code.

  4. Improve Class API design which is one of the primary benefits of TDD, lost to the lazy public manic people like me.



Oh, yes, an stop putting java semicolons in Ruby code. That really upsets the Ruby people.

Tests and Blank Lines

Add blank lines please.

This might sound stupid and, indeed, alternate DSL's for unit testing are making this less of an issue but there are still a lot of the old XUnit frameworks that prevent isolation of the 3 areas of your tests.

Every test you have needs to be setup, executed and validated. Let's start with a Java example.

public static void testSomething()
{
Address address = new Address();
address.setName("The House");
address.setLine1("1234 Street Ave");
address.setCity("Cityville");
address.setCountry("US");
address = dao.geocode(address);
assert_equals(-86.234, address.getLatitude());
assert_equals(46.234, address.getLongitude());
}


What does this test do? Which lines of code are being tested? Ok, lets try again with blank lines.

public static void testSomething()
{
Address address = new Address();
address.setName("The House");
address.setLine1("1234 Street Ave");
address.setCity("Cityville");
address.setCountry("US");

address = dao.geocode(address);

assert_equals(-86.234, address.getLatitude());
assert_equals(46.234, address.getLongitude());
}


Doesn't that help? A simple change and you can clearly see the three areas of your code.

I hear you shout "setup method", I know but junit sucks in that the only way to write enough tests with enough setup's is to have lots of separate test classes. Certainly go that way if you have a complex class to test but simpler stuff can be done in one class with a little setup and tests with blank lines.

OK, what is the future of these blank lines? Well, Ruby has unit test libraries like Shoulda that make these concepts easy to express.

context "an address" do

setup do
@address = Address.new(
:name => "The House",
:line1 => "1234 Street Ave",
:city => "Cityville",
:country => "US"
)
end

should "be geocoded to a specific lat and long" do

@address = @address.geocode

assert -86.234, @address.latitude
assert 46.234, @address.longitude
end
end


This allows us to separate and describe the areas of our tests, however, common usage has taken this API to the next level which, I think speaks to the need for the original idea behind the blank lines.

context "an address" do

setup do
@address = Address.new(
:name => "The House",
:line1 => "1234 Street Ave",
:city => "Cityville",
:country => "US"
)
end

context "when geocoded" do

setup do
@address = @address.geocode
end

should "have a specific latitude" do
assert -86.234, @address.latitude
end

should "have a specific longitude" do
assert 46.234, @address.longitude
end
end
end


As you can see, the use of the sub-context for each "test" and the use of the setup method to actually run the test, allows us to isolate the specifics of what the test is all about and describe each area.

3/11/2009

Extreme Arguments and the Slippery Slope

So often we hear doubters ripping into ideas for their "potential" for destroying the world we know. Why the crazy extreme?

Most recently it was argued that code refactoring was bad because a programmer will spend so much time "perfecting" the code that they will never finish the project.

Another, states that we spend so much time unit testing that we don't write production code.

Another that you have to "corrupt" your beautiful domain design so much to make it testable that it makes OO irrelevant.

The Republicans are doing with the whole stimulus thing. A few billion spent means that we are on the slippery slope that results in the government owning every house in the country.

The "Slipper Slope" argument is the favorite argument of the person that doesn't have an argument for the proposal on the table.

Perhaps we should attempt assess the benefits of a proposal based on the proposal.

If you don't understand why something is bad you should not announce your opinion about your fears of what it might lead to. If it ends up leading there, announce away, until then, lets improve our world one step at a time.

Sticking to the facts is the single hardest thing we do. Especially, since facts can be a little slippery themselves.