Archive for September, 2006

The Testing Anti-Patterns Drafts Vol. 1

Saturday, September 23rd, 2006

“The Testing Anti-Patterns Drafts” is a collaborative effort between Stuart “Stubs are evil” Caborn and myself, which aims to identify cases of Testing gone bad.

It consists of a single document that will undergo constant enhancements and modifications, in a “pair-authoring” manner, utilizing our respective weblogs as the platform.

We hope to get input from anyone following the document, our goal being to produce an interesting resource for the TDD, or Testing Oriented in general community.

Design Pervasive Testing

Both Stuart and I consider ourselves fortunate enough to work as members of teams where TDD is practiced by default.

There are two reasons beyond the obvious as to why I find it relatively harder to code in a non TDD approach. Test Driving my code enhances my vision on how to design/model/instrument my application’s universe. Also, starting with a test means work begins and ends with coding, not meetings, discussions or modeling our vision in pictures bound to be proven unrealistic when the first coding bottlenecks arise.

Having said that, testing properly is not easy. Past the simplistic examples, proper tests are hard work, often much harder than the actual code.

Encapsulation and Behavior are two of the most important characteristics of Object Oriented design. Applying them properly is difficult, and after all the hard work, testing Classes that are very concise about their behavior and very strict about what their peers can do with them, writing meaningful, readable, fine grained tests becomes a mission.

It’s the extra effort required that sometimes phases developers who end up taking shortcuts in order to facilitate testing.

Let’s look at an example:

public void testShouldProduceComplexObject() {
	ComplexObject expected = ObjectMother.getComplexObject();
	ComplexObject actual = classUnderTest.getComplexObject();
	assertEquals(expected, actual);
}

Obviously, such an assertion would only be valid if ComplexObject overrides the hashCode() and equals() methods. Countless times have I witnessed Classes implementing these two methods only to accommodate tests similar to the aforementioned example.

This is terminally wrong and a potential bug. Equality is an integral attribute of a Class’s behavior and should be strictly meaningful under the context of the Class’s definition.

I’m not aware of an easy way out of this sticky situation. Specific fields of the Class need to be tested for equality in isolation.

Does this mean that we need to expose all the Class fields we need to test by giving them public, or package level access? Not necessarily. In fact, not at all. After all, changing access levels would further compromise our Class’s behavior.

More and more, we have discovered Reflection to be an invaluable tool in our quest for less intrusive to purist OO design testing:

public void testShouldProduceComplexObject() {
	ComplexObject expected = ObjectMother.getComplexObject();
	ComplexObject actual = classUnderTest.getComplexObject();
	assertEquals(getPrivateField(expected, "fieldOne"),
		getPrivateField(actual, "fieldOne");
	assertEquals(getPrivateField(expected, "fieldTwo"),
		getPrivateField(actual, "fieldTwo");
	//etc...
}

If this were a container-bean type of Class with fifteen fields, that’s a lot typing we’d have to deal with. This is not necessarily bad for a Unit Test, but we could all do with less sore fingertips.

public void testShouldProduceComplexObject() {
	ComplexObject expected = ObjectMother.getComplexObject();
	ComplexObject actual = classUnderTest.getComplexObject();
	String[] fields = new String[] { “fieldOne”, [...], “fieldFifteen” };
	for (String field : fields) {
		assertEquals(getPrivateField(expected, field),
			getPrivateField(actual, field);
	}
}

TBC…

If you’d like to follow the discussion, feel free to grab The Testing Anti-Patterns Drafts feed.

A touch of coolness

Thursday, September 21st, 2006

Running svn info from inside your project’s Subversion working directory will produce output similar to:

Path: .
URL: http://svn.rockblood.com/solo/trunk
Repository UUID: 3b82abcc-450f-0410-a6ff-cb6cb9f014c2
Revision: 189
Node Kind: directory
Schedule: normal
Last Changed Author: george
Last Changed Rev: 189
Last Changed Date: 2006-09-09 00:19:04 +0100 (Sat, 09 Sep 2006)

At a first glance, there’s nothing special about this piece of information. Look closer, though, and you’ll notice it’s actually a YAML document.

A touch of YAML.load(execute("svn info")) in Ruby, and we’re in business. Another application’s output becomes a hash, array, or object in a matter of one single line of code.

I haven’t come up with the idea, by the way, just stumbled upon it whilst going through the code of the Rails continuous_builder plugin, so respect due.

Also, I’m not so sure if the SVN guys had that in mind when they had the info command output in such a format. Does anyone know if it is intentional or just a coincidence?

The possibilities of standardizing your app’s output in such a manner are vast and I know how my app’s standard out is going to look like from now on.

Getting rid of IoC

Sunday, September 10th, 2006

What is the point of IoC?

It’s not cleaner code. It’s not convenient unit testing.

It’s seamlessly interchanging implementations of interfaces.

I think you will agree with me on this: How often do you really need to do that? Almost never.

So go ahead and replace the following code:

class Rock {
	private Instrument guitar;

	public void setInstrument(Instrument instrument) {
		this.guitar = instrument;
	}
}

with:

class Rock {
	private Instrument guitar = new Guitar();
}

This is actually cleaner (one less method). And we probably got rid of some XML somewhere in our app…

So how do we unit test the Rock class by providing it a stubbed or mocked instrument? Easy: Reflection. Reflection has three really useful features: Get and set private field and invoke private method. So the test could be:

class RockTest extends TestCase {
	public void testShouldPlayGuitar() {
		Rock rock = new Rock();
		Instrument stubbedGuitar = RockObjectMother.gibsonSg();
		TestUtils.setPrivateField(rock, "guitar", stubbedGuitar)
		assertEquals("guitar bite", rock.play());
	}
}

Now, I’m not saying IoC is bad and I’m not saying don’t use IoC. What I’m saying is: Use IoC when you need it and use it for what it’s for.

Thanks to Stuart Caborn and David Reed for reminding me that Reflection is not all that bad.

The future of software is… Back to the basics

Sunday, September 10th, 2006

A little bit more than a couple of years ago Component Oriented Design was all the rage. Beyond Object Oriented Programming they said… For about a month.

The fine print, of course, mentioned that Components were not there to replace OOP, more like complement it.

I guess the books didn’t sell very well and as a result you hardly ever hear anyone mentioning Components these days.

Truth of the matter is, Components have always been there as an integral ingredient of OO. Because, if we ignore the attributes that were attached to them a few years ago to feed book pages (call me Web Services, Distributed, etc), a Component is essentially a bunch of Classes collaborating inside their little cosmos and communicating with the rest of the world through a narrow interface.

In its simplest form, say, a Java component, is some code in a package.

Writing a component is easy, provided we keep one simple rule in mind. The world is oblivious to what happens inside the component. The world is only interested in what the component can provide it with and what the component needs to perform its task. In other words, the world should only care calling the methods of a Component’s public Interface.

‘All this sounds so simple and basic and everybody knows about it since school…’ I can imagine you saying and a fair claim it is.

So why doesn’t anyone do it?

Blame whoever you want, but today’s Java development has reached a point where access levels, packages and interfaces have completely lost their meaning.

Here’s a few rules of thumb you might want to consider for designing more effectively:

Start by giving every new Class package level access instead of making it public. Same goes for non-private methods.

Don’t give private methods default access just to unit test them. Use reflection instead.

Do not give every class an Interface. Contrary to popular belief, Interfaces are not there to accommodate auto-wired Dependency Injection.

Create packages based on their Domain identity, not their type of functionality. For example, do com.universe.solarsystem.services and com.universe.solarsystem.dao instead of com.universe.services.solarsystem and com.universe.dao.solarsystem.

Treat packages (Components) they same way you treat classes. Decompose them based on responsibilities and make them remember to tell, don’t ask.

There’s an ancient OO paradigm called Encapsulation and it goes beyond Classes. Hide your Component’s internals and only expose what’s needed. Collaborators don’t care how the Component performs its magic.

In the vast majority of cases, it makes more sense to make code specific, instead of generic. Think of the small picture, then the bigger picture and then fit those in the Big Picture.

Get the basics right before you leverage the framework. And choose frameworks in a way that will suit your design instead of basing your design on Frameworks.

Mac OS, upgrade to Ruby 1.8.5

Tuesday, September 5th, 2006

Ruby 1.8.5

If you’re a Mac OS user into Ruby and haven’t done so already, go grab yourself a copy of Ruby 1.8.5.

Unpack and…

cd ruby-1.8.5

sudo make install-all

… and that’s it. Killer.

The Lost Arc

Monday, September 4th, 2006

Whatever happened to Arc?

I got excited by Paul Graham’s rhetorics about two years ago when I first read his pitch on Arc and I sure still do, every time I happen to go through it again.

A Language for Good Programmers - Target user: opposite of Java is a bold statement, but if it doesn’t get you excited, I have to admit it says a lot to me.

And Paul Graham is guy who has a lot to say and he definitely hits the spot more than often. And I quote:


If a language had twenty separate users, meaning twenty users who decided on their own to use it, I’d consider it to be real. Getting there can’t be easy. I would not be surprised if it is harder to get from zero to twenty than from twenty to a thousand. The best way to get those initial twenty users is probably to use a trojan horse: to give people an application they want, which happens to be written in the new language.

Rings any bells?

Paul speaks of programming languages eventually making it to the mainstream and defining software building manifestos on the shoulders of a few distinctively above average, over-dedicated hackers. And, oh, how I like associating with this theory. Not that I ever put myself next to any of the afore suggested luminaries, but you can always dream. And try…

I’m guessing Paul didn’t have Ruby in mind when he came up with the above observation, but C also - much more so - falls into that category - a language built for creating Unix, which became better and popular alongside the great Operating System. And I dare anyone question C’s momentum as the most important programming language ever, maybe after Assembly.

So where’s Arc now, five years down the line of its announcement? Is it going to remain the ever Unfinished Dialect of Lisp?

One of the most difficult pills to swallow is witnessing people who inspire(d) you go down the path they once damned.

I might certainly be misinterpreting facts here, but it seems to me Paul Graham is nowadays dedicating most of his efforts in becoming some sort of ex-hacker, Venture Capital, geek-friendly Business Angel. Which reads, plainly and simply, d o u g h.

And that is pretty close to how Paul condemned Java as hype software, or a language designed for average programmers that has to put safety first. Java is where it is today because some people knew how to sell it. And Paul has realized he has a talent for selling stuff, thus, potentially abandoned the idealistic goal of creating the best - to his convictions - programming language and decided to fund/coach graduates in garages promote their next-MySpace idea to suits who will help make everyone rich.

Nothing wrong with that, wish I could come up with Goose With the Golden Egg 2.0. But let me tell you what. Not Unix, nor C, were built with material profits in mind. At least not up front.

Of course, I could very well be wrong. Arc might be just around the corner and it might turn out to be the missing programming language. And this whole Venture Capital issue is just a side project…

Man, I hope I’m wrong…